1 Get Data Ready

1.1 Repeat the EDA part

<U+393C><U+3E31>lubridate<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>lubridate<U+393C><U+3E32> is imported by <U+393C><U+3E31>tidyverse<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>scales<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>scales<U+393C><U+3E32> is imported by <U+393C><U+3E31>kableExtra<U+393C><U+3E32>, <U+393C><U+3E31>ggplot2<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>forcats<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>forcats<U+393C><U+3E32> is imported by <U+393C><U+3E31>haven<U+393C><U+3E32>, <U+393C><U+3E31>tidyverse<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>stringr<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>stringr<U+393C><U+3E32> is imported by <U+393C><U+3E31>tidyverse<U+393C><U+3E32>, <U+393C><U+3E31>lubridate<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>dplyr<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>dplyr<U+393C><U+3E32> is imported by <U+393C><U+3E31>broom<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>purrr<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>purrr<U+393C><U+3E32> is imported by <U+393C><U+3E31>tidyselect<U+393C><U+3E32>, <U+393C><U+3E31>modelr<U+393C><U+3E32>, <U+393C><U+3E31>broom<U+393C><U+3E32>, <U+393C><U+3E31>tidyr<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>readr<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>readr<U+393C><U+3E32> is imported by <U+393C><U+3E31>tidyverse<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>tidyr<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>tidyr<U+393C><U+3E32> is imported by <U+393C><U+3E31>tidyverse<U+393C><U+3E32>, <U+393C><U+3E31>broom<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>tibble<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>tibble<U+393C><U+3E32> is imported by <U+393C><U+3E31>haven<U+393C><U+3E32>, <U+393C><U+3E31>dplyr<U+393C><U+3E32>, <U+393C><U+3E31>modelr<U+393C><U+3E32>, <U+393C><U+3E31>broom<U+393C><U+3E32>, <U+393C><U+3E31>readr<U+393C><U+3E32>, <U+393C><U+3E31>ggplot2<U+393C><U+3E32>, <U+393C><U+3E31>tidyr<U+393C><U+3E32> so cannot be unloaded<U+393C><U+3E31>ggplot2<U+393C><U+3E32> namespace cannot be unloaded:
  namespace <U+393C><U+3E31>ggplot2<U+393C><U+3E32> is imported by <U+393C><U+3E31>tidyverse<U+393C><U+3E32> so cannot be unloaded
[[1]]
NULL

[[2]]
NULL

[[3]]
NULL

[[4]]
NULL

[[5]]
NULL

[[6]]
NULL

[[7]]
NULL

[[8]]
NULL

[[9]]
NULL

[[10]]
NULL

[[11]]
NULL

[[12]]
NULL

[[13]]
NULL

[[14]]
NULL

[[15]]
NULL

[[16]]
NULL

[[17]]
NULL

[[18]]
NULL
package <U+393C><U+3E31>kableExtra<U+393C><U+3E32> was built under R version 3.5.2package <U+393C><U+3E31>formattable<U+393C><U+3E32> was built under R version 3.5.2package <U+393C><U+3E31>pastecs<U+393C><U+3E32> was built under R version 3.5.3package <U+393C><U+3E31>directlabels<U+393C><U+3E32> was built under R version 3.5.3package <U+393C><U+3E31>Metrics<U+393C><U+3E32> was built under R version 3.5.3
number of columns of result is not a multiple of vector length (arg 1)33566 parsing failures.
row # A tibble: 5 x 5 col     row col                  expected              actual file                expected   <int> <chr>                <chr>                 <chr>  <chr>               actual 1  1038 cummulative_gross_r~ no trailing characte~ .3     'BOOKINGS_ATLCP.cs~ file 2  1038 OTB_rev              no trailing characte~ .3     'BOOKINGS_ATLCP.cs~ row 3  1038 OTB_rev_to_survive   no trailing characte~ .3     'BOOKINGS_ATLCP.cs~ col 4  1039 cummulative_gross_r~ no trailing characte~ .3     'BOOKINGS_ATLCP.cs~ expected 5  1039 OTB_rev              no trailing characte~ .3     'BOOKINGS_ATLCP.cs~
... ................................. ... ............................................................................. ........ .......................................................................................................................................................................................................... ...... ...................................................................................................... .... ...................................................................................................... ... ...................................................................................................... ... ...................................................................................................... ........ ......................................................................................................
See problems(...) for more details.
number of columns of result is not a multiple of vector length (arg 1)31164 parsing failures.
row # A tibble: 5 x 5 col     row col                 expected               actual file                 expected   <int> <chr>               <chr>                  <chr>  <chr>                actual 1  2136 cummulative_cxl_rev no trailing characters .1     'BOOKINGS_NYCHA.csv' file 2  2137 cummulative_cxl_rev no trailing characters .1     'BOOKINGS_NYCHA.csv' row 3  2138 daily_cxl_rev       no trailing characters .1     'BOOKINGS_NYCHA.csv' col 4  2138 cummulative_cxl_rev no trailing characters .1     'BOOKINGS_NYCHA.csv' expected 5  2139 OTB_rev_to_be_cxl   no trailing characters .1     'BOOKINGS_NYCHA.csv'
... ................................. ... .............................................................................. ........ ........................................................................................................................................................................................................... ...... ....................................................................................................... .... ....................................................................................................... ... ....................................................................................................... ... ....................................................................................................... ........ .......................................................................................................
See problems(...) for more details.
# change date fields to date
hot1$stay_dt <- as.Date(hot1$stay_dt, "%m/%d/%Y")
hot1$booking_dt <- as.Date(hot1$booking_dt, "%m/%d/%Y")
hot2$stay_dt <- as.Date(hot2$stay_dt, "%m/%d/%Y")
hot2$booking_dt <- as.Date(hot2$booking_dt, "%m/%d/%Y")
#create field for non-numerical dow
hot1$day_of_week <- as.factor(hot1$dow)
hot2$day_of_week <- as.factor(hot2$dow)
# Reserve last 3 weeks data as Validation Data and the prior are Training Data
h1_train <- hot1[hot1$stay_dt <= (max(hot1$stay_dt) - 21),]
h2_train <- hot2[hot2$stay_dt <= (max(hot2$stay_dt) - 21),]

1.1.1 Hotel 1 - ATL

#add price and otb_cxl_rate to h1_train
h1_train <-  h1_train %>%
  filter(OTB!=0) %>% 
  mutate(price = OTB_rev/OTB, OTB_cxl_rate = OTB_to_be_cxl/OTB)
h1_train <- h1_train %>%
  filter(days_prior < 33)
h1_train <- h1_train %>%
  mutate(day_type = case_when(day_of_week == '7' ~ 'weekend',
                              day_of_week == '1' ~ 'weekend', 
                              TRUE ~'weekday'))
h1_train$month = month(h1_train$stay_dt)

1.1.1.1 Grouping method 1

# make this a group in h1_train
h1_train_1 <- h1_train %>%
      mutate(prod_group_perc = case_when(product_type == 'OPAQUE' ~ 'OP/FENC',
                                         product_type == 'FENCED' ~ 'OP/FENC',
                                         product_type == 'CORPORATE' ~ 'CORP/BUS',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'CORP/BUS',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'MEM/OTHER',
                                         product_type == 'OTHER' ~ 'MEM/OTHER',
                                         product_type == 'UNFENCED' ~ 'GOV/UNFENC',
                                         product_type == 'GOVERNMENT' ~ 'GOV/UNFENC'))

1.1.1.2 Grouping method 2

#Create this group
h1_train_2 <- h1_train %>%
      mutate(prod_group_behav = case_when(product_type == 'OPAQUE' ~ 'OP/FENC/OTH',
                                         product_type == 'FENCED' ~ 'OP/FENC/OTH',
                                         product_type == 'CORPORATE' ~ 'CORPORATE',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'GOV/BUS/MEM',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'GOV/BUS/MEM',
                                         product_type == 'OTHER' ~ 'OP/FENC/OTH',
                                         product_type == 'UNFENCED' ~ 'UNFENCED',
                                         product_type == 'GOVERNMENT' ~ 'GOV/BUS/MEM'))

1.1.1.3 Grouping method 3

#Create this group
h1_train_3 <- h1_train %>%
      mutate(prod_group_cxl_rate = case_when(product_type == 'OPAQUE' ~ 'GOV/UNFEN/OP',
                                         product_type == 'FENCED' ~ 'CORP/FEN/MEM',
                                         product_type == 'CORPORATE' ~ 'CORP/FEN/MEM',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'OTH/BTA',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'MEMBERSHIP' ~ 'CORP/FEN/MEM',
                                         product_type == 'OTHER' ~ 'OTH/BTA',
                                         product_type == 'UNFENCED' ~ 'GOV/UNFEN/OP',
                                         product_type == 'GOVERNMENT' ~ 'GOV/UNFEN/OP'))

1.1.2 Hotel 2 - NY

#add price and otb_cxl_rate to h1_train
h2_train <-  h2_train %>%
  filter(OTB!=0) %>% 
  mutate(price = OTB_rev/OTB, OTB_cxl_rate = OTB_to_be_cxl/OTB)
h2_train <- h2_train %>%
  filter(days_prior < 32)
h2_train <- h2_train %>%
  mutate(day_type = case_when(day_of_week == '7' ~ 'weekend',
                              day_of_week == '1' ~ 'weekend', 
                              TRUE ~'weekday'))
h2_train$month = month(h2_train$stay_dt)

1.1.2.1 Grouping Method 1

#make these groups
h2_train_1 <- h2_train %>%
      mutate(prod_group_perc = case_when(product_type == 'OPAQUE' ~ 'OP/FENC/OTH',
                                         product_type == 'FENCED' ~ 'OP/FENC/OTH',
                                         product_type == 'CORPORATE' ~ 'CORP/GROUP/TACT',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'UNF/WHOLE/MEM/BUS',
                                         product_type == 'GROUP' ~ 'CORP/GROUP/TACT',
                                         product_type == 'TACTICAL MARKETING' ~ 'CORP/GROUP/TACT',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'UNF/WHOLE/MEM/BUS',
                                         product_type == 'OTHER' ~ 'OP/FENC/OTH',
                                         product_type == 'UNFENCED' ~ 'UNF/WHOLE/MEM/BUS',
                                         product_type == 'GOVERNMENT' ~ 'GOVERNMENT',
                                         product_type == 'WHOLESALE' ~ 'UNF/WHOLE/MEM/BUS'))

1.1.2.2 Grouping Method 2

#make this a group
h2_train_2 <- h2_train %>%
      mutate(prod_group_behav = case_when(product_type == 'OPAQUE' ~ 'OTH/OPA/FEN',
                                         product_type == 'FENCED' ~ 'OTH/OPA/FEN',
                                         product_type == 'CORPORATE' ~ 'CORP/MEMB/WHOLE',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'BTA/UNFEN/CORP/MM',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'TACTICAL MARKETING' ~ 'TACT/WHOLE',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'BTA/UNFEN/CORP/MM',
                                         product_type == 'OTHER' ~ 'OTH/OPA/FEN',
                                         product_type == 'UNFENCED' ~ 'BTA/UNFEN/CORP/MM',
                                         product_type == 'GOVERNMENT' ~ 'GOVERNMENT',
                                         product_type == 'WHOLESALE' ~ 'TACT/WHOLE'))

2 Naive Modeling Begins Here

#get just the last three weeks for test data 
hot1 <-  hot1[hot1$stay_dt >(max(hot1$stay_dt) - 21),]
hot2 <-  hot2[hot2$stay_dt >(max(hot2$stay_dt) - 21),]
#truncate the days prior for test data
hot1 <- hot1 %>% 
          filter(days_prior < 33)
hot2 <- hot2 %>%
          filter(days_prior < 32)
#add price, cxl rate
hot1<-  hot1 %>%
  filter(OTB!=0) %>% 
  mutate(price = OTB_rev/OTB, OTB_cxl_rate = OTB_to_be_cxl/OTB)
hot2 <-  hot2 %>%
  filter(OTB!=0) %>% 
  mutate(price = OTB_rev/OTB, OTB_cxl_rate = OTB_to_be_cxl/OTB)
#add month
hot1$month = month(hot1$stay_dt)
hot2$month = month(hot2$stay_dt)
#add weekday/weekend
hot1 <- hot1 %>%
  mutate(day_type = case_when(day_of_week == '7' ~ 'weekend',
                              day_of_week == '1' ~ 'weekend', 
                              TRUE ~'weekday'))
hot2 <- hot2 %>%
  mutate(day_type = case_when(day_of_week == '7' ~ 'weekend',
                              day_of_week == '1' ~ 'weekend', 
                              TRUE ~'weekday'))

2.1 Hotel 1 - ATL

2.1.1 CXL Rate by days prior

# calculate cancellation rate just by days prior
a_dp <- h1_train %>%
      select(days_prior, OTB, OTB_to_be_cxl, OTB_cxl_rate) %>%
      group_by(days_prior) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_test <- hot1 %>%
      select(days_prior, OTB, OTB_to_be_cxl, OTB_cxl_rate, OTB_cxl_rate) %>%
      group_by(days_prior) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_mod <- left_join(a_dp, a_dp_test, by = 'days_prior')
a_dp_mod

2.1.2 CXL Rate by groups, days prior, and weekdays

# use weekdays and grouping one
# get test data ready
hot1_test_1 <- hot1 %>%
      mutate(prod_group_perc = case_when(product_type == 'OPAQUE' ~ 'OP/FENC',
                                         product_type == 'FENCED' ~ 'OP/FENC',
                                         product_type == 'CORPORATE' ~ 'CORP/BUS',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'CORP/BUS',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'MEM/OTHER',
                                         product_type == 'OTHER' ~ 'MEM/OTHER',
                                         product_type == 'UNFENCED' ~ 'GOV/UNFENC',
                                         product_type == 'GOVERNMENT' ~ 'GOV/UNFENC'))
hot1_test_2 <- hot1 %>%
      mutate(prod_group_behav = case_when(product_type == 'OPAQUE' ~ 'OP/FENC/OTH',
                                         product_type == 'FENCED' ~ 'OP/FENC/OTH',
                                         product_type == 'CORPORATE' ~ 'CORPORATE',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'GOV/BUS/MEM',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'GOV/BUS/MEM',
                                         product_type == 'OTHER' ~ 'OP/FENC/OTH',
                                         product_type == 'UNFENCED' ~ 'UNFENCED',
                                         product_type == 'GOVERNMENT' ~ 'GOV/BUS/MEM'))
hot1_test_3 <- hot1 %>%
      mutate(prod_group_cxl_rate = case_when(product_type == 'OPAQUE' ~ 'GOV/UNFEN/OP',
                                         product_type == 'FENCED' ~ 'CORP/FEN/MEM',
                                         product_type == 'CORPORATE' ~ 'CORP/FEN/MEM',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'OTH/BTA',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'CORP/FEN/MEM',
                                         product_type == 'OTHER' ~ 'OTH/BTA',
                                         product_type == 'UNFENCED' ~ 'GOV/UNFEN/OP',
                                         product_type == 'GOVERNMENT' ~ 'GOV/UNFEN/OP'))
#group 1's CXL Rate by groups, days prior, and weekdays
a_dp_grp1_wd <- h1_train_1 %>%
      select(days_prior, prod_group_perc, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_perc, day_of_week) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp1_wd_test <- hot1_test_1 %>%
      select(days_prior, prod_group_perc, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_perc, day_of_week) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp1_wd_mod <- left_join(a_dp_grp1_wd, a_dp_grp1_wd_test, by = c('days_prior', 'prod_group_perc', 'day_of_week'))
a_dp_grp1_wd_mod
#group 2's CXL Rate by groups, days prior, and weekdays
a_dp_grp2_wd <- h1_train_2 %>%
      select(days_prior, prod_group_behav, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_behav, day_of_week) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp2_wd_test <- hot1_test_2 %>%
      select(days_prior, prod_group_behav, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_behav, day_of_week) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp2_wd_mod <- left_join(a_dp_grp2_wd, a_dp_grp2_wd_test, by = c('days_prior', 'prod_group_behav', 'day_of_week'))
a_dp_grp2_wd_mod
#group 3 and days prior
a_dp_grp3_wd <- h1_train_3 %>%
      select(days_prior, prod_group_cxl_rate, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_cxl_rate, day_of_week) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp3_wd_test <- hot1_test_3 %>%
      select(days_prior, prod_group_cxl_rate, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_cxl_rate, day_of_week) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp3_wd_mod <- left_join(a_dp_grp3_wd, a_dp_grp3_wd_test, by = c('days_prior', 'prod_group_cxl_rate', 'day_of_week'))
a_dp_grp3_wd_mod

2.1.3 CXL Rate by groups, days prior, day type

#group 1's CXL Rate by groups, days prior,day type
a_dp_grp1_dtp <- h1_train_1 %>%
      select(days_prior, prod_group_perc, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_perc, day_type) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp1_dtp_test <- hot1_test_1 %>%
      select(days_prior, prod_group_perc, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_perc, day_type) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp1_dtp_mod <- left_join(a_dp_grp1_dtp, a_dp_grp1_dtp_test, by = c('days_prior', 'prod_group_perc', 'day_type'))
a_dp_grp1_dtp_mod
#group 2's CXL Rate by groups, days prior,day type
a_dp_grp2_dtp <- h1_train_2 %>%
      select(days_prior, prod_group_behav, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_behav, day_type) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp2_dtp_test <- hot1_test_2 %>%
      select(days_prior, prod_group_behav, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_behav, day_type) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp2_dtp_mod <- left_join(a_dp_grp2_dtp, a_dp_grp2_dtp_test, by = c('days_prior', 'prod_group_behav', 'day_type'))
a_dp_grp2_dtp_mod
#group 3's CXL Rate by groups, days prior,day type
a_dp_grp3_dtp <- h1_train_3 %>%
      select(days_prior, prod_group_cxl_rate, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_cxl_rate, day_type) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp3_dtp_test <- hot1_test_3 %>%
      select(days_prior, prod_group_cxl_rate, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_cxl_rate, day_type) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
a_dp_grp3_dtp_mod <- left_join(a_dp_grp3_dtp, a_dp_grp3_dtp_test, by = c('days_prior', 'prod_group_cxl_rate', 'day_type'))
a_dp_grp3_dtp_mod

2.2 Hotel 2 - NY

2.2.1 CXL Rate and days prior

# calculate cancellation rate just by days prior and 
n_dp <- h2_train %>%
      select(days_prior, OTB, OTB_to_be_cxl, OTB_cxl_rate) %>%
      group_by(days_prior) %>%
      summarise(predict_cxl_rate = mean(OTB_cxl_rate))
n_dp_test <- hot2 %>%
      select(days_prior, OTB, OTB_to_be_cxl, OTB_cxl_rate, OTB_cxl_rate) %>%
      group_by(days_prior) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_mod <- left_join(n_dp, n_dp_test, by = 'days_prior')
n_dp_mod

2.2.2 CXL Rate by groups, days prior, and weekdays

# use weekdays and grouping one
# get test data ready
hot2_test_1 <- hot2 %>%
      mutate(prod_group_perc = case_when(product_type == 'OPAQUE' ~ 'OP/FENC/OTH',
                                         product_type == 'FENCED' ~ 'OP/FENC/OTH',
                                         product_type == 'CORPORATE' ~ 'CORP/GROUP/TACT',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'UNF/WHOLE/MEM/BUS',
                                         product_type == 'GROUP' ~ 'CORP/GROUP/TACT',
                                         product_type == 'TACTICAL MARKETING' ~ 'CORP/GROUP/TACT',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'UNF/WHOLE/MEM/BUS',
                                         product_type == 'OTHER' ~ 'OP/FENC/OTH',
                                         product_type == 'UNFENCED' ~ 'UNF/WHOLE/MEM/BUS',
                                         product_type == 'GOVERNMENT' ~ 'GOVERNMENT',
                                         product_type == 'WHOLESALE' ~ 'UNF/WHOLE/MEM/BUS'))
hot2_test_2 <- hot2 %>%
      mutate(prod_group_behav = case_when(product_type == 'OPAQUE' ~ 'OTH/OPA/FEN',
                                         product_type == 'FENCED' ~ 'OTH/OPA/FEN',
                                         product_type == 'CORPORATE' ~ 'CORP/MEMB/WHOLE',
                                         product_type == 'BUSINESS TRAVEL AGENCIES' ~ 'BTA/UNFEN/CORP/MM',
                                         product_type == 'GROUP' ~ 'GROUP',
                                         product_type == 'TACTICAL MARKETING' ~ 'TACT/WHOLE',
                                         product_type == 'MEMBERSHIP MARKETING' ~ 'BTA/UNFEN/CORP/MM',
                                         product_type == 'OTHER' ~ 'OTH/OPA/FEN',
                                         product_type == 'UNFENCED' ~ 'BTA/UNFEN/CORP/MM',
                                         product_type == 'GOVERNMENT' ~ 'GOVERNMENT',
                                         product_type == 'WHOLESALE' ~ 'TACT/WHOLE'))
#group 1's CXL Rate by groups, days prior, and weekdays
n_dp_grp1_wd <- h2_train_1 %>%
      select(days_prior, prod_group_perc, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_perc, day_of_week) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp1_wd_test <- hot2_test_1 %>%
      select(days_prior, prod_group_perc, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_perc, day_of_week) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp1_wd_mod <- left_join(n_dp_grp1_wd, n_dp_grp1_wd_test, by = c('days_prior', 'prod_group_perc', 'day_of_week'))
n_dp_grp1_wd_mod
#group 2's CXL Rate by groups, days prior, and weekdays
n_dp_grp2_wd <- h2_train_2 %>%
      select(days_prior, prod_group_behav, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_behav, day_of_week) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp2_wd_test <- hot2_test_2 %>%
      select(days_prior, prod_group_behav, day_of_week, OTB, OTB_to_be_cxl) %>%
      group_by(days_prior, prod_group_behav, day_of_week) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp2_wd_mod <- left_join(n_dp_grp2_wd, n_dp_grp2_wd_test, by = c('days_prior', 'prod_group_behav', 'day_of_week'))
n_dp_grp2_wd_mod

2.2.3 CXL Rate by groups, days prior, day type

#group 1's CXL Rate by groups, days prior,day type
n_dp_grp1_dtp <- h2_train_1 %>%
      select(days_prior, prod_group_perc, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_perc, day_type) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp1_dtp_test <- hot2_test_1 %>%
      select(days_prior, prod_group_perc, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_perc, day_type) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp1_dtp_mod <- left_join(n_dp_grp1_dtp, n_dp_grp1_dtp_test, by = c('days_prior', 'prod_group_perc', 'day_type'))
n_dp_grp1_dtp_mod
#group 2's CXL Rate by groups, days prior,day type
n_dp_grp2_dtp <- h2_train_2 %>%
      select(days_prior, prod_group_behav, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_behav, day_type) %>%
      summarise(predict_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp2_dtp_test <- hot2_test_2 %>%
      select(days_prior, prod_group_behav, day_type, OTB, OTB_to_be_cxl, month) %>%
      group_by(days_prior, prod_group_behav, day_type) %>%
      summarise(true_cxl_rate = sum(OTB_to_be_cxl)/sum(OTB))
n_dp_grp2_dtp_mod <- left_join(n_dp_grp2_dtp, n_dp_grp2_dtp_test, by = c('days_prior', 'prod_group_behav', 'day_type'))
n_dp_grp2_dtp_mod

3 Performance Evaluation

3.1 Hotel 1 - ATL

3.1.1 CXL Rate by days prior

# forecast otb to survive
a_dp_fcs <- left_join(hot1, a_dp_mod, by="days_prior") %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
# MAE
a_dp_mae <- a_dp_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
a_dp_mae
# MAPE: the OTB_to_survive has 0 values. So ask Professor
a_dp_mape <- a_dp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range) %>% 
  summarise(meanAPE = mape(OTB_to_survive, fcst_svv))
a_dp_mape
# MASE: 
## Avg survival rate:
avg_svv_rt <- sum(h1_train$OTB_to_survive)/sum(h1_train$OTB)
## MASE
a_dp_mase <- a_dp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
a_dp_mase

3.1.2 CXL Rate by groups, days prior, and weekdays

3.1.2.1 Grouping method 1

# forecast otb to survive
a_dp_grp1_wd_fcs <- left_join(hot1_test_1, a_dp_grp1_wd_mod, by=c("days_prior", "day_of_week", "prod_group_perc")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
a_dp_grp1_wd_fcs
# MAE
a_dp_grp1_wd_mae <- a_dp_grp1_wd_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
a_dp_grp1_wd_mae
# MAPE 
# MASE
a_dp_grp1_wd_mase <- a_dp_grp1_wd_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
a_dp_grp1_wd_mase

3.1.2.2 Grouping method 2

# forecast otb to survive
a_dp_grp2_wd_fcs <- left_join(hot1_test_2, a_dp_grp2_wd_mod, by=c("days_prior", "day_of_week", "prod_group_behav")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
a_dp_grp2_wd_fcs
# MAE
a_dp_grp2_wd_mae <- a_dp_grp2_wd_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_behav) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
a_dp_grp2_wd_mae
# MAPE 
# MASE
a_dp_grp2_wd_mase <- a_dp_grp2_wd_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range, day_of_week, prod_group_behav) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
a_dp_grp2_wd_mase

3.1.2.3 Grouping method 3

# forecast otb to survive
a_dp_grp3_wd_fcs <- left_join(hot1_test_3, a_dp_grp3_wd_mod, by=c("days_prior", "day_of_week", "prod_group_cxl_rate")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
a_dp_grp3_wd_fcs
# MAE
a_dp_grp3_wd_mae <- a_dp_grp3_wd_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_cxl_rate) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
a_dp_grp3_wd_mae
# MAPE 
# MASE
a_dp_grp3_wd_mase <- a_dp_grp3_wd_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range, day_of_week, prod_group_cxl_rate) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
a_dp_grp3_wd_mase

3.1.3 CXL Rate by groups, days prior, day type

3.1.3.1 Grouping method 1

# forecast otb to survive
a_dp_grp1_dtp_fcs <- left_join(hot1_test_1, a_dp_grp1_dtp_mod, by=c("days_prior", "day_type", "prod_group_perc")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
a_dp_grp1_dtp_fcs
# MAE
a_dp_grp1_dtp_mae <- a_dp_grp1_dtp_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
a_dp_grp1_dtp_mae
# MAPE 
# MASE
a_dp_grp1_dtp_mase <- a_dp_grp1_dtp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
a_dp_grp1_dtp_mase

3.1.3.2 Grouping method 2

# forecast otb to survive
a_dp_grp2_dtp_fcs <- left_join(hot1_test_2, a_dp_grp2_dtp_mod, by=c("days_prior", "day_type", "prod_group_behav")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
a_dp_grp2_dtp_fcs
# MAE
a_dp_grp2_dtp_mae <- a_dp_grp2_dtp_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_type, prod_group_behav) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
a_dp_grp2_dtp_mae
# MAPE 
# MASE
a_dp_grp2_dtp_mase <- a_dp_grp2_dtp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range, day_type, prod_group_behav) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
a_dp_grp2_dtp_mase

3.1.3.3 Grouping method 3

# forecast otb to survive
a_dp_grp3_dtp_fcs <- left_join(hot1_test_3, a_dp_grp3_dtp_mod, by=c("days_prior", "day_type", "prod_group_cxl_rate")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
a_dp_grp3_dtp_fcs
# MAE
a_dp_grp3_dtp_mae <- a_dp_grp3_dtp_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_type, prod_group_cxl_rate) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
a_dp_grp3_dtp_mae
# MAPE 
# MASE
a_dp_grp3_dtp_mase <- a_dp_grp3_dtp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range, day_type, prod_group_cxl_rate) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
a_dp_grp3_dtp_mase

3.2 Hotel 2 - ATL

3.2.1 CXL Rate by days prior

# forecast otb to survive
n_dp_fcs <- left_join(hot2, n_dp_mod, by="days_prior") %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
# MAE
n_dp_mae <- n_dp_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
n_dp_mae
# MAPE: the OTB_to_survive doesn't have 0 values.
n_dp_mape <- n_dp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range) %>% 
  summarise(meanAPE = mape(OTB_to_survive, fcst_svv))
n_dp_mape
# MASE: 
## Avg survival rate:
avg_svv_rt_2 <- sum(h2_train$OTB_to_survive)/sum(h2_train$OTB)
## MASE
n_dp_mase <- n_dp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
n_dp_mase

3.2.2 CXL Rate by groups, days prior, and weekdays

3.2.2.1 Grouping method 1

# forecast otb to survive
n_dp_grp1_wd_fcs <- left_join(hot2_test_1, n_dp_grp1_wd_mod, by=c("days_prior", "day_of_week", "prod_group_perc")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
n_dp_grp1_wd_fcs
# MAE
n_dp_grp1_wd_mae <- n_dp_grp1_wd_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
n_dp_grp1_wd_mae
# MAPE: the OTB_to_survive doesn't have 0 values.
n_dp_grp1_wd_mape <- n_dp_grp1_wd_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanAPE = mape(OTB_to_survive, fcst_svv))
n_dp_grp1_wd_mape
# MASE
n_dp_grp1_wd_mase <- n_dp_grp1_wd_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt_2*OTB)) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
n_dp_grp1_wd_mase

3.2.2.2 Grouping method 2

# forecast otb to survive
n_dp_grp2_wd_fcs <- left_join(hot2_test_2, n_dp_grp2_wd_mod, by=c("days_prior", "day_of_week", "prod_group_behav")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
n_dp_grp2_wd_fcs
# MAE
n_dp_grp2_wd_mae <- n_dp_grp2_wd_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_behav) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
n_dp_grp2_wd_mae
# MAPE: the OTB_to_survive doesn't have 0 values.
n_dp_grp2_wd_mape <- n_dp_grp2_wd_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_behav) %>% 
  summarise(meanAPE = mape(OTB_to_survive, fcst_svv))
n_dp_grp2_wd_mape
# MASE
n_dp_grp2_wd_mase <- n_dp_grp2_wd_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt_2*OTB)) %>% 
  group_by(dp_range, day_of_week, prod_group_behav) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
n_dp_grp2_wd_mase

3.2.3 CXL Rate by groups, days prior, day type

3.2.3.1 Grouping method 1

# forecast otb to survive
n_dp_grp1_dtp_fcs <- left_join(hot2_test_1, n_dp_grp1_dtp_mod, by=c("days_prior", "day_type", "prod_group_perc")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
n_dp_grp1_dtp_fcs
# MAE
n_dp_grp1_dtp_mae <- n_dp_grp1_dtp_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
n_dp_grp1_dtp_mae
# MAPE: the OTB_to_survive doesn't have 0 values.
n_dp_grp1_dtp_mape <- n_dp_grp1_dtp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_type, prod_group_perc) %>% 
  summarise(meanAPE = mape(OTB_to_survive, fcst_svv))
n_dp_grp1_dtp_mape
# MASE
n_dp_grp1_dtp_mase <- n_dp_grp1_dtp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt*OTB)) %>% 
  group_by(dp_range, day_of_week, prod_group_perc) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
n_dp_grp1_dtp_mase

3.2.3.2 Grouping method 2

# forecast otb to survive
n_dp_grp2_dtp_fcs <- left_join(hot2_test_2, n_dp_grp2_dtp_mod, by=c("days_prior", "day_type", "prod_group_behav")) %>% 
  mutate(fcst_svv = OTB-OTB*predict_cxl_rate)
n_dp_grp2_dtp_fcs
# MAE
n_dp_grp2_dtp_mae <- n_dp_grp2_dtp_fcs %>% 
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_type, prod_group_behav) %>% 
  summarise(meanAE = mae(OTB_to_survive, fcst_svv))
n_dp_grp2_dtp_mae
# MAPE: the OTB_to_survive doesn't have 0 values.
n_dp_grp2_dtp_mape <- n_dp_grp2_dtp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32')) %>% 
  group_by(dp_range, day_type, prod_group_behav) %>% 
  summarise(meanAPE = mape(OTB_to_survive, fcst_svv))
n_dp_grp2_dtp_mape
# MASE
n_dp_grp2_dtp_mase <- n_dp_grp2_dtp_fcs %>%  
  filter(days_prior!=0) %>% 
  mutate(dp_range = case_when(days_prior >=1 & days_prior<=7 ~ '1_7',
                                  days_prior >=8 & days_prior<=14 ~ '8_14',
                                  days_prior >=15 & days_prior<=21 ~ '15_21',
                                  days_prior >=22 & days_prior<=28 ~ '22_28',
                                  days_prior >=29 ~ '29_32'),
         abs_diff_1=abs(OTB_to_survive-fcst_svv),
         abs_diff_2=abs(OTB_to_survive-avg_svv_rt_2*OTB)) %>% 
  group_by(dp_range, day_type, prod_group_behav) %>% 
  summarise(meanASE = sum(abs_diff_1)/sum(abs_diff_2))
n_dp_grp2_dtp_mase
LS0tDQp0aXRsZTogIkhvdGVsIENhbmNlbGxhdGlvbiAtIE5haXZlIE1vZGVsIg0KYXV0aG9yOiAiQ2FpdGxpbiBIb3dhbnNreSAmIFdlaSBMaSINCmRhdGU6ICJgciBmb3JtYXQoU3lzLnRpbWUoKSwgJyVCICVkLCAlWScpYCINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogJzMnDQogIGh0bWxfbm90ZWJvb2s6DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2M6IHllcw0KICAgIHRvY19kZXB0aDogMw0KICAgIHRvY19mbG9hdDogeWVzDQotLS0NCg0KI19fR2V0IERhdGEgUmVhZHlfXw0KIyNfX1JlcGVhdCB0aGUgRURBIHBhcnRfXw0KYGBge3IgbWVzc2FnZSA9IEZBTFNFLCBlY2hvID0gRkFMU0UsIGVycm9yID0gRkFMU0V9DQojIENsZWFyIGVudmlyb25tZW50IG9mIHZhcmlhYmxlcyBhbmQgZnVuY3Rpb25zDQpybShsaXN0ID0gbHMoYWxsID0gVFJVRSkpIA0KIyBDbGVhciBlbnZpcm9ubWV0IG9mIHBhY2thZ2VzDQppZihpcy5udWxsKHNlc3Npb25JbmZvKCkkb3RoZXJQa2dzKSA9PSBGQUxTRSlsYXBwbHkocGFzdGUoInBhY2thZ2U6IiwgbmFtZXMoc2Vzc2lvbkluZm8oKSRvdGhlclBrZ3MpLCBzZXA9IiIpLCBkZXRhY2gsIGNoYXJhY3Rlci5vbmx5ID0gVFJVRSwgdW5sb2FkID0gVFJVRSkNCmBgYA0KDQpgYGB7ciBtZXNzYWdlID0gRkFMU0UsIGVjaG8gPSBGQUxTRSwgZXJyb3IgPSBGQUxTRX0NCmxpYnJhcnkodGlkeXZlcnNlKSANCmxpYnJhcnkoZHBseXIpICMgam9pbnMNCiNsaWJyYXJ5KGphbml0b3IpICMgcHJldHR5IGNyb3NzLXRhYnMNCmxpYnJhcnkoa2FibGVFeHRyYSkgIyBwcmV0dHkgaHRtbCB0YWJsZXMNCmxpYnJhcnkoZm9ybWF0dGFibGUpDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkoc2NhbGVzKQ0KbGlicmFyeShwYXN0ZWNzKQ0KbGlicmFyeShHR2FsbHkpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZGlyZWN0bGFiZWxzKQ0KbGlicmFyeShNZXRyaWNzKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBlcnJvciA9IEZBTFNFfQ0KIyBkaXNhYmxlIHNjaWVudGlmaWMgbm90YXRpb24gaW4gUg0Kb3B0aW9ucyhzY2lwZW49OTk5KQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2UgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBlcnJvciA9IEZBTFNFfQ0KIyBsb2FkIHRoZSBkYXRhIGZpbGVzDQpob3QxIDwtIHJlYWRfY3N2KCdCT09LSU5HU19BVExDUC5jc3YnKQ0KaG90MiA8LSByZWFkX2NzdignQk9PS0lOR1NfTllDSEEuY3N2JykNCg0KYGBgDQoNCg0KYGBge3J9DQojIGNoYW5nZSBkYXRlIGZpZWxkcyB0byBkYXRlDQpob3QxJHN0YXlfZHQgPC0gYXMuRGF0ZShob3QxJHN0YXlfZHQsICIlbS8lZC8lWSIpDQpob3QxJGJvb2tpbmdfZHQgPC0gYXMuRGF0ZShob3QxJGJvb2tpbmdfZHQsICIlbS8lZC8lWSIpDQpob3QyJHN0YXlfZHQgPC0gYXMuRGF0ZShob3QyJHN0YXlfZHQsICIlbS8lZC8lWSIpDQpob3QyJGJvb2tpbmdfZHQgPC0gYXMuRGF0ZShob3QyJGJvb2tpbmdfZHQsICIlbS8lZC8lWSIpDQoNCiNjcmVhdGUgZmllbGQgZm9yIG5vbi1udW1lcmljYWwgZG93DQpob3QxJGRheV9vZl93ZWVrIDwtIGFzLmZhY3Rvcihob3QxJGRvdykNCmhvdDIkZGF5X29mX3dlZWsgPC0gYXMuZmFjdG9yKGhvdDIkZG93KQ0KYGBgDQoNCmBgYHtyfQ0KIyBSZXNlcnZlIGxhc3QgMyB3ZWVrcyBkYXRhIGFzIFZhbGlkYXRpb24gRGF0YSBhbmQgdGhlIHByaW9yIGFyZSBUcmFpbmluZyBEYXRhDQpoMV90cmFpbiA8LSBob3QxW2hvdDEkc3RheV9kdCA8PSAobWF4KGhvdDEkc3RheV9kdCkgLSAyMSksXQ0KaDJfdHJhaW4gPC0gaG90Mltob3QyJHN0YXlfZHQgPD0gKG1heChob3QyJHN0YXlfZHQpIC0gMjEpLF0NCmBgYA0KDQojIyNfX0hvdGVsIDEgLSBBVExfXw0KYGBge3J9DQojYWRkIHByaWNlIGFuZCBvdGJfY3hsX3JhdGUgdG8gaDFfdHJhaW4NCg0KaDFfdHJhaW4gPC0gIGgxX3RyYWluICU+JQ0KICBmaWx0ZXIoT1RCIT0wKSAlPiUgDQogIG11dGF0ZShwcmljZSA9IE9UQl9yZXYvT1RCLCBPVEJfY3hsX3JhdGUgPSBPVEJfdG9fYmVfY3hsL09UQikNCg0KaDFfdHJhaW4gPC0gaDFfdHJhaW4gJT4lDQogIGZpbHRlcihkYXlzX3ByaW9yIDwgMzMpDQoNCmgxX3RyYWluIDwtIGgxX3RyYWluICU+JQ0KICBtdXRhdGUoZGF5X3R5cGUgPSBjYXNlX3doZW4oZGF5X29mX3dlZWsgPT0gJzcnIH4gJ3dlZWtlbmQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5X29mX3dlZWsgPT0gJzEnIH4gJ3dlZWtlbmQnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfid3ZWVrZGF5JykpDQpoMV90cmFpbiRtb250aCA9IG1vbnRoKGgxX3RyYWluJHN0YXlfZHQpDQpgYGANCg0KIyMjI19fR3JvdXBpbmcgbWV0aG9kIDFfXw0KYGBge3J9DQojIG1ha2UgdGhpcyBhIGdyb3VwIGluIGgxX3RyYWluDQpoMV90cmFpbl8xIDwtIGgxX3RyYWluICU+JQ0KICAgICAgbXV0YXRlKHByb2RfZ3JvdXBfcGVyYyA9IGNhc2Vfd2hlbihwcm9kdWN0X3R5cGUgPT0gJ09QQVFVRScgfiAnT1AvRkVOQycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnRkVOQ0VEJyB+ICdPUC9GRU5DJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdDT1JQT1JBVEUnIH4gJ0NPUlAvQlVTJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdCVVNJTkVTUyBUUkFWRUwgQUdFTkNJRVMnIH4gJ0NPUlAvQlVTJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdHUk9VUCcgfiAnR1JPVVAnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ01FTUJFUlNISVAgTUFSS0VUSU5HJyB+ICdNRU0vT1RIRVInLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ09USEVSJyB+ICdNRU0vT1RIRVInLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1VORkVOQ0VEJyB+ICdHT1YvVU5GRU5DJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdHT1ZFUk5NRU5UJyB+ICdHT1YvVU5GRU5DJykpDQpgYGANCg0KIyMjI19fR3JvdXBpbmcgbWV0aG9kIDJfXw0KYGBge3J9DQojQ3JlYXRlIHRoaXMgZ3JvdXANCg0KaDFfdHJhaW5fMiA8LSBoMV90cmFpbiAlPiUNCiAgICAgIG11dGF0ZShwcm9kX2dyb3VwX2JlaGF2ID0gY2FzZV93aGVuKHByb2R1Y3RfdHlwZSA9PSAnT1BBUVVFJyB+ICdPUC9GRU5DL09USCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnRkVOQ0VEJyB+ICdPUC9GRU5DL09USCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnQ09SUE9SQVRFJyB+ICdDT1JQT1JBVEUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0JVU0lORVNTIFRSQVZFTCBBR0VOQ0lFUycgfiAnR09WL0JVUy9NRU0nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0dST1VQJyB+ICdHUk9VUCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnTUVNQkVSU0hJUCBNQVJLRVRJTkcnIH4gJ0dPVi9CVVMvTUVNJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdPVEhFUicgfiAnT1AvRkVOQy9PVEgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1VORkVOQ0VEJyB+ICdVTkZFTkNFRCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR09WRVJOTUVOVCcgfiAnR09WL0JVUy9NRU0nKSkNCmBgYA0KDQojIyMjX19Hcm91cGluZyBtZXRob2QgM19fDQpgYGB7cn0NCiNDcmVhdGUgdGhpcyBncm91cA0KDQpoMV90cmFpbl8zIDwtIGgxX3RyYWluICU+JQ0KICAgICAgbXV0YXRlKHByb2RfZ3JvdXBfY3hsX3JhdGUgPSBjYXNlX3doZW4ocHJvZHVjdF90eXBlID09ICdPUEFRVUUnIH4gJ0dPVi9VTkZFTi9PUCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnRkVOQ0VEJyB+ICdDT1JQL0ZFTi9NRU0nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0NPUlBPUkFURScgfiAnQ09SUC9GRU4vTUVNJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdCVVNJTkVTUyBUUkFWRUwgQUdFTkNJRVMnIH4gJ09USC9CVEEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0dST1VQJyB+ICdHUk9VUCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnTUVNQkVSU0hJUCcgfiAnQ09SUC9GRU4vTUVNJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdPVEhFUicgfiAnT1RIL0JUQScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnVU5GRU5DRUQnIH4gJ0dPVi9VTkZFTi9PUCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR09WRVJOTUVOVCcgfiAnR09WL1VORkVOL09QJykpDQpgYGANCg0KDQojIyNfX0hvdGVsIDIgLSBOWV9fDQpgYGB7cn0NCiNhZGQgcHJpY2UgYW5kIG90Yl9jeGxfcmF0ZSB0byBoMV90cmFpbg0KDQpoMl90cmFpbiA8LSAgaDJfdHJhaW4gJT4lDQogIGZpbHRlcihPVEIhPTApICU+JSANCiAgbXV0YXRlKHByaWNlID0gT1RCX3Jldi9PVEIsIE9UQl9jeGxfcmF0ZSA9IE9UQl90b19iZV9jeGwvT1RCKQ0KDQpoMl90cmFpbiA8LSBoMl90cmFpbiAlPiUNCiAgZmlsdGVyKGRheXNfcHJpb3IgPCAzMikNCg0KaDJfdHJhaW4gPC0gaDJfdHJhaW4gJT4lDQogIG11dGF0ZShkYXlfdHlwZSA9IGNhc2Vfd2hlbihkYXlfb2Zfd2VlayA9PSAnNycgfiAnd2Vla2VuZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlfb2Zfd2VlayA9PSAnMScgfiAnd2Vla2VuZCcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+J3dlZWtkYXknKSkNCmgyX3RyYWluJG1vbnRoID0gbW9udGgoaDJfdHJhaW4kc3RheV9kdCkNCmBgYA0KDQojIyMjX19Hcm91cGluZyBNZXRob2QgMV9fDQpgYGB7cn0NCiNtYWtlIHRoZXNlIGdyb3Vwcw0KaDJfdHJhaW5fMSA8LSBoMl90cmFpbiAlPiUNCiAgICAgIG11dGF0ZShwcm9kX2dyb3VwX3BlcmMgPSBjYXNlX3doZW4ocHJvZHVjdF90eXBlID09ICdPUEFRVUUnIH4gJ09QL0ZFTkMvT1RIJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdGRU5DRUQnIH4gJ09QL0ZFTkMvT1RIJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdDT1JQT1JBVEUnIH4gJ0NPUlAvR1JPVVAvVEFDVCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnQlVTSU5FU1MgVFJBVkVMIEFHRU5DSUVTJyB+ICdVTkYvV0hPTEUvTUVNL0JVUycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR1JPVVAnIH4gJ0NPUlAvR1JPVVAvVEFDVCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnVEFDVElDQUwgTUFSS0VUSU5HJyB+ICdDT1JQL0dST1VQL1RBQ1QnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ01FTUJFUlNISVAgTUFSS0VUSU5HJyB+ICdVTkYvV0hPTEUvTUVNL0JVUycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnT1RIRVInIH4gJ09QL0ZFTkMvT1RIJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdVTkZFTkNFRCcgfiAnVU5GL1dIT0xFL01FTS9CVVMnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0dPVkVSTk1FTlQnIH4gJ0dPVkVSTk1FTlQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1dIT0xFU0FMRScgfiAnVU5GL1dIT0xFL01FTS9CVVMnKSkNCmBgYA0KDQojIyMjX19Hcm91cGluZyBNZXRob2QgMiBfXw0KYGBge3J9DQojbWFrZSB0aGlzIGEgZ3JvdXANCmgyX3RyYWluXzIgPC0gaDJfdHJhaW4gJT4lDQogICAgICBtdXRhdGUocHJvZF9ncm91cF9iZWhhdiA9IGNhc2Vfd2hlbihwcm9kdWN0X3R5cGUgPT0gJ09QQVFVRScgfiAnT1RIL09QQS9GRU4nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0ZFTkNFRCcgfiAnT1RIL09QQS9GRU4nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0NPUlBPUkFURScgfiAnQ09SUC9NRU1CL1dIT0xFJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdCVVNJTkVTUyBUUkFWRUwgQUdFTkNJRVMnIH4gJ0JUQS9VTkZFTi9DT1JQL01NJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdHUk9VUCcgfiAnR1JPVVAnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1RBQ1RJQ0FMIE1BUktFVElORycgfiAnVEFDVC9XSE9MRScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnTUVNQkVSU0hJUCBNQVJLRVRJTkcnIH4gJ0JUQS9VTkZFTi9DT1JQL01NJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdPVEhFUicgfiAnT1RIL09QQS9GRU4nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1VORkVOQ0VEJyB+ICdCVEEvVU5GRU4vQ09SUC9NTScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR09WRVJOTUVOVCcgfiAnR09WRVJOTUVOVCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnV0hPTEVTQUxFJyB+ICdUQUNUL1dIT0xFJykpDQoNCmBgYA0KDQoNCiNfX05haXZlIE1vZGVsaW5nIEJlZ2lucyBIZXJlX18NCmBgYHtyfQ0KI2dldCBqdXN0IHRoZSBsYXN0IHRocmVlIHdlZWtzIGZvciB0ZXN0IGRhdGEgDQpob3QxIDwtICBob3QxW2hvdDEkc3RheV9kdCA+KG1heChob3QxJHN0YXlfZHQpIC0gMjEpLF0NCmhvdDIgPC0gIGhvdDJbaG90MiRzdGF5X2R0ID4obWF4KGhvdDIkc3RheV9kdCkgLSAyMSksXQ0KYGBgDQoNCmBgYHtyfQ0KI3RydW5jYXRlIHRoZSBkYXlzIHByaW9yIGZvciB0ZXN0IGRhdGENCmhvdDEgPC0gaG90MSAlPiUgDQogICAgICAgICAgZmlsdGVyKGRheXNfcHJpb3IgPCAzMykNCg0KaG90MiA8LSBob3QyICU+JQ0KICAgICAgICAgIGZpbHRlcihkYXlzX3ByaW9yIDwgMzIpDQoNCiNhZGQgcHJpY2UsIGN4bCByYXRlDQpob3QxPC0gIGhvdDEgJT4lDQogIGZpbHRlcihPVEIhPTApICU+JSANCiAgbXV0YXRlKHByaWNlID0gT1RCX3Jldi9PVEIsIE9UQl9jeGxfcmF0ZSA9IE9UQl90b19iZV9jeGwvT1RCKQ0KDQpob3QyIDwtICBob3QyICU+JQ0KICBmaWx0ZXIoT1RCIT0wKSAlPiUgDQogIG11dGF0ZShwcmljZSA9IE9UQl9yZXYvT1RCLCBPVEJfY3hsX3JhdGUgPSBPVEJfdG9fYmVfY3hsL09UQikNCg0KI2FkZCBtb250aA0KaG90MSRtb250aCA9IG1vbnRoKGhvdDEkc3RheV9kdCkNCmhvdDIkbW9udGggPSBtb250aChob3QyJHN0YXlfZHQpDQoNCiNhZGQgd2Vla2RheS93ZWVrZW5kDQpob3QxIDwtIGhvdDEgJT4lDQogIG11dGF0ZShkYXlfdHlwZSA9IGNhc2Vfd2hlbihkYXlfb2Zfd2VlayA9PSAnNycgfiAnd2Vla2VuZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlfb2Zfd2VlayA9PSAnMScgfiAnd2Vla2VuZCcsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+J3dlZWtkYXknKSkNCmhvdDIgPC0gaG90MiAlPiUNCiAgbXV0YXRlKGRheV90eXBlID0gY2FzZV93aGVuKGRheV9vZl93ZWVrID09ICc3JyB+ICd3ZWVrZW5kJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheV9vZl93ZWVrID09ICcxJyB+ICd3ZWVrZW5kJywgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4nd2Vla2RheScpKQ0KYGBgDQoNCg0KIyNfX0hvdGVsIDEgLSBBVExfXw0KIyMjX19DWEwgUmF0ZSBieSBkYXlzIHByaW9yX18NCmBgYHtyfQ0KIyBjYWxjdWxhdGUgY2FuY2VsbGF0aW9uIHJhdGUganVzdCBieSBkYXlzIHByaW9yDQphX2RwIDwtIGgxX3RyYWluICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIE9UQiwgT1RCX3RvX2JlX2N4bCwgT1RCX2N4bF9yYXRlKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IpICU+JQ0KICAgICAgc3VtbWFyaXNlKHByZWRpY3RfY3hsX3JhdGUgPSBzdW0oT1RCX3RvX2JlX2N4bCkvc3VtKE9UQikpDQoNCmFfZHBfdGVzdCA8LSBob3QxICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIE9UQiwgT1RCX3RvX2JlX2N4bCwgT1RCX2N4bF9yYXRlLCBPVEJfY3hsX3JhdGUpICU+JQ0KICAgICAgZ3JvdXBfYnkoZGF5c19wcmlvcikgJT4lDQogICAgICBzdW1tYXJpc2UodHJ1ZV9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0KYV9kcF9tb2QgPC0gbGVmdF9qb2luKGFfZHAsIGFfZHBfdGVzdCwgYnkgPSAnZGF5c19wcmlvcicpDQphX2RwX21vZA0KYGBgDQoNCiMjI19fQ1hMIFJhdGUgYnkgZ3JvdXBzLCBkYXlzIHByaW9yLCBhbmQgd2Vla2RheXNfXw0KYGBge3J9DQojIHVzZSB3ZWVrZGF5cyBhbmQgZ3JvdXBpbmcgb25lDQojIGdldCB0ZXN0IGRhdGEgcmVhZHkNCg0KaG90MV90ZXN0XzEgPC0gaG90MSAlPiUNCiAgICAgIG11dGF0ZShwcm9kX2dyb3VwX3BlcmMgPSBjYXNlX3doZW4ocHJvZHVjdF90eXBlID09ICdPUEFRVUUnIH4gJ09QL0ZFTkMnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0ZFTkNFRCcgfiAnT1AvRkVOQycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnQ09SUE9SQVRFJyB+ICdDT1JQL0JVUycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnQlVTSU5FU1MgVFJBVkVMIEFHRU5DSUVTJyB+ICdDT1JQL0JVUycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR1JPVVAnIH4gJ0dST1VQJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdNRU1CRVJTSElQIE1BUktFVElORycgfiAnTUVNL09USEVSJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdPVEhFUicgfiAnTUVNL09USEVSJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdVTkZFTkNFRCcgfiAnR09WL1VORkVOQycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR09WRVJOTUVOVCcgfiAnR09WL1VORkVOQycpKQ0KaG90MV90ZXN0XzIgPC0gaG90MSAlPiUNCiAgICAgIG11dGF0ZShwcm9kX2dyb3VwX2JlaGF2ID0gY2FzZV93aGVuKHByb2R1Y3RfdHlwZSA9PSAnT1BBUVVFJyB+ICdPUC9GRU5DL09USCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnRkVOQ0VEJyB+ICdPUC9GRU5DL09USCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnQ09SUE9SQVRFJyB+ICdDT1JQT1JBVEUnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0JVU0lORVNTIFRSQVZFTCBBR0VOQ0lFUycgfiAnR09WL0JVUy9NRU0nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0dST1VQJyB+ICdHUk9VUCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnTUVNQkVSU0hJUCBNQVJLRVRJTkcnIH4gJ0dPVi9CVVMvTUVNJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdPVEhFUicgfiAnT1AvRkVOQy9PVEgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1VORkVOQ0VEJyB+ICdVTkZFTkNFRCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR09WRVJOTUVOVCcgfiAnR09WL0JVUy9NRU0nKSkNCg0KaG90MV90ZXN0XzMgPC0gaG90MSAlPiUNCiAgICAgIG11dGF0ZShwcm9kX2dyb3VwX2N4bF9yYXRlID0gY2FzZV93aGVuKHByb2R1Y3RfdHlwZSA9PSAnT1BBUVVFJyB+ICdHT1YvVU5GRU4vT1AnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0ZFTkNFRCcgfiAnQ09SUC9GRU4vTUVNJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdDT1JQT1JBVEUnIH4gJ0NPUlAvRkVOL01FTScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnQlVTSU5FU1MgVFJBVkVMIEFHRU5DSUVTJyB+ICdPVEgvQlRBJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdHUk9VUCcgfiAnR1JPVVAnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ01FTUJFUlNISVAgTUFSS0VUSU5HJyB+ICdDT1JQL0ZFTi9NRU0nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ09USEVSJyB+ICdPVEgvQlRBJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdVTkZFTkNFRCcgfiAnR09WL1VORkVOL09QJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdHT1ZFUk5NRU5UJyB+ICdHT1YvVU5GRU4vT1AnKSkNCmBgYA0KDQpgYGB7cn0NCiNncm91cCAxJ3MgQ1hMIFJhdGUgYnkgZ3JvdXBzLCBkYXlzIHByaW9yLCBhbmQgd2Vla2RheXMNCmFfZHBfZ3JwMV93ZCA8LSBoMV90cmFpbl8xICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfcGVyYywgZGF5X29mX3dlZWssIE9UQiwgT1RCX3RvX2JlX2N4bCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV9vZl93ZWVrKSAlPiUNCiAgICAgIHN1bW1hcmlzZShwcmVkaWN0X2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQphX2RwX2dycDFfd2RfdGVzdCA8LSBob3QxX3Rlc3RfMSAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV9vZl93ZWVrLCBPVEIsIE9UQl90b19iZV9jeGwpICU+JQ0KICAgICAgZ3JvdXBfYnkoZGF5c19wcmlvciwgcHJvZF9ncm91cF9wZXJjLCBkYXlfb2Zfd2VlaykgJT4lDQogICAgICBzdW1tYXJpc2UodHJ1ZV9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0KYV9kcF9ncnAxX3dkX21vZCA8LSBsZWZ0X2pvaW4oYV9kcF9ncnAxX3dkLCBhX2RwX2dycDFfd2RfdGVzdCwgYnkgPSBjKCdkYXlzX3ByaW9yJywgJ3Byb2RfZ3JvdXBfcGVyYycsICdkYXlfb2Zfd2VlaycpKQ0KYV9kcF9ncnAxX3dkX21vZA0KYGBgDQoNCmBgYHtyfQ0KI2dyb3VwIDIncyBDWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsIGFuZCB3ZWVrZGF5cw0KYV9kcF9ncnAyX3dkIDwtIGgxX3RyYWluXzIgJT4lDQogICAgICBzZWxlY3QoZGF5c19wcmlvciwgcHJvZF9ncm91cF9iZWhhdiwgZGF5X29mX3dlZWssIE9UQiwgT1RCX3RvX2JlX2N4bCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2JlaGF2LCBkYXlfb2Zfd2VlaykgJT4lDQogICAgICBzdW1tYXJpc2UocHJlZGljdF9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0KYV9kcF9ncnAyX3dkX3Rlc3QgPC0gaG90MV90ZXN0XzIgJT4lDQogICAgICBzZWxlY3QoZGF5c19wcmlvciwgcHJvZF9ncm91cF9iZWhhdiwgZGF5X29mX3dlZWssIE9UQiwgT1RCX3RvX2JlX2N4bCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2JlaGF2LCBkYXlfb2Zfd2VlaykgJT4lDQogICAgICBzdW1tYXJpc2UodHJ1ZV9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0KYV9kcF9ncnAyX3dkX21vZCA8LSBsZWZ0X2pvaW4oYV9kcF9ncnAyX3dkLCBhX2RwX2dycDJfd2RfdGVzdCwgYnkgPSBjKCdkYXlzX3ByaW9yJywgJ3Byb2RfZ3JvdXBfYmVoYXYnLCAnZGF5X29mX3dlZWsnKSkNCmFfZHBfZ3JwMl93ZF9tb2QNCmBgYA0KDQpgYGB7cn0NCiNncm91cCAzIGFuZCBkYXlzIHByaW9yDQphX2RwX2dycDNfd2QgPC0gaDFfdHJhaW5fMyAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2N4bF9yYXRlLCBkYXlfb2Zfd2VlaywgT1RCLCBPVEJfdG9fYmVfY3hsKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfY3hsX3JhdGUsIGRheV9vZl93ZWVrKSAlPiUNCiAgICAgIHN1bW1hcmlzZShwcmVkaWN0X2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQphX2RwX2dycDNfd2RfdGVzdCA8LSBob3QxX3Rlc3RfMyAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2N4bF9yYXRlLCBkYXlfb2Zfd2VlaywgT1RCLCBPVEJfdG9fYmVfY3hsKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfY3hsX3JhdGUsIGRheV9vZl93ZWVrKSAlPiUNCiAgICAgIHN1bW1hcmlzZSh0cnVlX2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQphX2RwX2dycDNfd2RfbW9kIDwtIGxlZnRfam9pbihhX2RwX2dycDNfd2QsIGFfZHBfZ3JwM193ZF90ZXN0LCBieSA9IGMoJ2RheXNfcHJpb3InLCAncHJvZF9ncm91cF9jeGxfcmF0ZScsICdkYXlfb2Zfd2VlaycpKQ0KYV9kcF9ncnAzX3dkX21vZA0KYGBgDQoNCiMjI19fQ1hMIFJhdGUgYnkgZ3JvdXBzLCBkYXlzIHByaW9yLCBkYXkgdHlwZV9fDQoNCmBgYHtyfQ0KI2dyb3VwIDEncyBDWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsZGF5IHR5cGUNCmFfZHBfZ3JwMV9kdHAgPC0gaDFfdHJhaW5fMSAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV90eXBlLCBPVEIsIE9UQl90b19iZV9jeGwsIG1vbnRoKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfcGVyYywgZGF5X3R5cGUpICU+JQ0KICAgICAgc3VtbWFyaXNlKHByZWRpY3RfY3hsX3JhdGUgPSBzdW0oT1RCX3RvX2JlX2N4bCkvc3VtKE9UQikpDQoNCmFfZHBfZ3JwMV9kdHBfdGVzdCA8LSBob3QxX3Rlc3RfMSAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV90eXBlLCBPVEIsIE9UQl90b19iZV9jeGwsIG1vbnRoKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfcGVyYywgZGF5X3R5cGUpICU+JQ0KICAgICAgc3VtbWFyaXNlKHRydWVfY3hsX3JhdGUgPSBzdW0oT1RCX3RvX2JlX2N4bCkvc3VtKE9UQikpDQoNCmFfZHBfZ3JwMV9kdHBfbW9kIDwtIGxlZnRfam9pbihhX2RwX2dycDFfZHRwLCBhX2RwX2dycDFfZHRwX3Rlc3QsIGJ5ID0gYygnZGF5c19wcmlvcicsICdwcm9kX2dyb3VwX3BlcmMnLCAnZGF5X3R5cGUnKSkNCmFfZHBfZ3JwMV9kdHBfbW9kDQpgYGANCg0KYGBge3J9DQojZ3JvdXAgMidzIENYTCBSYXRlIGJ5IGdyb3VwcywgZGF5cyBwcmlvcixkYXkgdHlwZQ0KYV9kcF9ncnAyX2R0cCA8LSBoMV90cmFpbl8yICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfYmVoYXYsIGRheV90eXBlLCBPVEIsIE9UQl90b19iZV9jeGwsIG1vbnRoKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfYmVoYXYsIGRheV90eXBlKSAlPiUNCiAgICAgIHN1bW1hcmlzZShwcmVkaWN0X2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQphX2RwX2dycDJfZHRwX3Rlc3QgPC0gaG90MV90ZXN0XzIgJT4lDQogICAgICBzZWxlY3QoZGF5c19wcmlvciwgcHJvZF9ncm91cF9iZWhhdiwgZGF5X3R5cGUsIE9UQiwgT1RCX3RvX2JlX2N4bCwgbW9udGgpICU+JQ0KICAgICAgZ3JvdXBfYnkoZGF5c19wcmlvciwgcHJvZF9ncm91cF9iZWhhdiwgZGF5X3R5cGUpICU+JQ0KICAgICAgc3VtbWFyaXNlKHRydWVfY3hsX3JhdGUgPSBzdW0oT1RCX3RvX2JlX2N4bCkvc3VtKE9UQikpDQoNCmFfZHBfZ3JwMl9kdHBfbW9kIDwtIGxlZnRfam9pbihhX2RwX2dycDJfZHRwLCBhX2RwX2dycDJfZHRwX3Rlc3QsIGJ5ID0gYygnZGF5c19wcmlvcicsICdwcm9kX2dyb3VwX2JlaGF2JywgJ2RheV90eXBlJykpDQphX2RwX2dycDJfZHRwX21vZA0KYGBgDQoNCmBgYHtyfQ0KI2dyb3VwIDMncyBDWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsZGF5IHR5cGUNCmFfZHBfZ3JwM19kdHAgPC0gaDFfdHJhaW5fMyAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2N4bF9yYXRlLCBkYXlfdHlwZSwgT1RCLCBPVEJfdG9fYmVfY3hsLCBtb250aCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2N4bF9yYXRlLCBkYXlfdHlwZSkgJT4lDQogICAgICBzdW1tYXJpc2UocHJlZGljdF9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0KYV9kcF9ncnAzX2R0cF90ZXN0IDwtIGhvdDFfdGVzdF8zICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfY3hsX3JhdGUsIGRheV90eXBlLCBPVEIsIE9UQl90b19iZV9jeGwsIG1vbnRoKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfY3hsX3JhdGUsIGRheV90eXBlKSAlPiUNCiAgICAgIHN1bW1hcmlzZSh0cnVlX2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQphX2RwX2dycDNfZHRwX21vZCA8LSBsZWZ0X2pvaW4oYV9kcF9ncnAzX2R0cCwgYV9kcF9ncnAzX2R0cF90ZXN0LCBieSA9IGMoJ2RheXNfcHJpb3InLCAncHJvZF9ncm91cF9jeGxfcmF0ZScsICdkYXlfdHlwZScpKQ0KYV9kcF9ncnAzX2R0cF9tb2QNCmBgYA0KDQoNCiMjX19Ib3RlbCAyIC0gTllfXw0KIyMjX19DWEwgUmF0ZSBhbmQgZGF5cyBwcmlvcl9fDQpgYGB7cn0NCiMgY2FsY3VsYXRlIGNhbmNlbGxhdGlvbiByYXRlIGp1c3QgYnkgZGF5cyBwcmlvciBhbmQgDQpuX2RwIDwtIGgyX3RyYWluICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIE9UQiwgT1RCX3RvX2JlX2N4bCwgT1RCX2N4bF9yYXRlKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IpICU+JQ0KICAgICAgc3VtbWFyaXNlKHByZWRpY3RfY3hsX3JhdGUgPSBtZWFuKE9UQl9jeGxfcmF0ZSkpDQoNCm5fZHBfdGVzdCA8LSBob3QyICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIE9UQiwgT1RCX3RvX2JlX2N4bCwgT1RCX2N4bF9yYXRlLCBPVEJfY3hsX3JhdGUpICU+JQ0KICAgICAgZ3JvdXBfYnkoZGF5c19wcmlvcikgJT4lDQogICAgICBzdW1tYXJpc2UodHJ1ZV9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0Kbl9kcF9tb2QgPC0gbGVmdF9qb2luKG5fZHAsIG5fZHBfdGVzdCwgYnkgPSAnZGF5c19wcmlvcicpDQpuX2RwX21vZA0KYGBgDQoNCiMjI19fQ1hMIFJhdGUgYnkgZ3JvdXBzLCBkYXlzIHByaW9yLCBhbmQgd2Vla2RheXNfXw0KYGBge3J9DQojIHVzZSB3ZWVrZGF5cyBhbmQgZ3JvdXBpbmcgb25lDQojIGdldCB0ZXN0IGRhdGEgcmVhZHkNCg0KaG90Ml90ZXN0XzEgPC0gaG90MiAlPiUNCiAgICAgIG11dGF0ZShwcm9kX2dyb3VwX3BlcmMgPSBjYXNlX3doZW4ocHJvZHVjdF90eXBlID09ICdPUEFRVUUnIH4gJ09QL0ZFTkMvT1RIJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdGRU5DRUQnIH4gJ09QL0ZFTkMvT1RIJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdDT1JQT1JBVEUnIH4gJ0NPUlAvR1JPVVAvVEFDVCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnQlVTSU5FU1MgVFJBVkVMIEFHRU5DSUVTJyB+ICdVTkYvV0hPTEUvTUVNL0JVUycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR1JPVVAnIH4gJ0NPUlAvR1JPVVAvVEFDVCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnVEFDVElDQUwgTUFSS0VUSU5HJyB+ICdDT1JQL0dST1VQL1RBQ1QnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ01FTUJFUlNISVAgTUFSS0VUSU5HJyB+ICdVTkYvV0hPTEUvTUVNL0JVUycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnT1RIRVInIH4gJ09QL0ZFTkMvT1RIJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdVTkZFTkNFRCcgfiAnVU5GL1dIT0xFL01FTS9CVVMnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0dPVkVSTk1FTlQnIH4gJ0dPVkVSTk1FTlQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1dIT0xFU0FMRScgfiAnVU5GL1dIT0xFL01FTS9CVVMnKSkNCmhvdDJfdGVzdF8yIDwtIGhvdDIgJT4lDQogICAgICBtdXRhdGUocHJvZF9ncm91cF9iZWhhdiA9IGNhc2Vfd2hlbihwcm9kdWN0X3R5cGUgPT0gJ09QQVFVRScgfiAnT1RIL09QQS9GRU4nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0ZFTkNFRCcgfiAnT1RIL09QQS9GRU4nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ0NPUlBPUkFURScgfiAnQ09SUC9NRU1CL1dIT0xFJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdCVVNJTkVTUyBUUkFWRUwgQUdFTkNJRVMnIH4gJ0JUQS9VTkZFTi9DT1JQL01NJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdHUk9VUCcgfiAnR1JPVVAnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1RBQ1RJQ0FMIE1BUktFVElORycgfiAnVEFDVC9XSE9MRScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnTUVNQkVSU0hJUCBNQVJLRVRJTkcnIH4gJ0JUQS9VTkZFTi9DT1JQL01NJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvZHVjdF90eXBlID09ICdPVEhFUicgfiAnT1RIL09QQS9GRU4nLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcm9kdWN0X3R5cGUgPT0gJ1VORkVOQ0VEJyB+ICdCVEEvVU5GRU4vQ09SUC9NTScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnR09WRVJOTUVOVCcgfiAnR09WRVJOTUVOVCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHByb2R1Y3RfdHlwZSA9PSAnV0hPTEVTQUxFJyB+ICdUQUNUL1dIT0xFJykpDQoNCmBgYA0KDQpgYGB7cn0NCiNncm91cCAxJ3MgQ1hMIFJhdGUgYnkgZ3JvdXBzLCBkYXlzIHByaW9yLCBhbmQgd2Vla2RheXMNCm5fZHBfZ3JwMV93ZCA8LSBoMl90cmFpbl8xICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfcGVyYywgZGF5X29mX3dlZWssIE9UQiwgT1RCX3RvX2JlX2N4bCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV9vZl93ZWVrKSAlPiUNCiAgICAgIHN1bW1hcmlzZShwcmVkaWN0X2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQpuX2RwX2dycDFfd2RfdGVzdCA8LSBob3QyX3Rlc3RfMSAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV9vZl93ZWVrLCBPVEIsIE9UQl90b19iZV9jeGwpICU+JQ0KICAgICAgZ3JvdXBfYnkoZGF5c19wcmlvciwgcHJvZF9ncm91cF9wZXJjLCBkYXlfb2Zfd2VlaykgJT4lDQogICAgICBzdW1tYXJpc2UodHJ1ZV9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0Kbl9kcF9ncnAxX3dkX21vZCA8LSBsZWZ0X2pvaW4obl9kcF9ncnAxX3dkLCBuX2RwX2dycDFfd2RfdGVzdCwgYnkgPSBjKCdkYXlzX3ByaW9yJywgJ3Byb2RfZ3JvdXBfcGVyYycsICdkYXlfb2Zfd2VlaycpKQ0Kbl9kcF9ncnAxX3dkX21vZA0KYGBgDQoNCmBgYHtyfQ0KI2dyb3VwIDIncyBDWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsIGFuZCB3ZWVrZGF5cw0Kbl9kcF9ncnAyX3dkIDwtIGgyX3RyYWluXzIgJT4lDQogICAgICBzZWxlY3QoZGF5c19wcmlvciwgcHJvZF9ncm91cF9iZWhhdiwgZGF5X29mX3dlZWssIE9UQiwgT1RCX3RvX2JlX2N4bCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2JlaGF2LCBkYXlfb2Zfd2VlaykgJT4lDQogICAgICBzdW1tYXJpc2UocHJlZGljdF9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0Kbl9kcF9ncnAyX3dkX3Rlc3QgPC0gaG90Ml90ZXN0XzIgJT4lDQogICAgICBzZWxlY3QoZGF5c19wcmlvciwgcHJvZF9ncm91cF9iZWhhdiwgZGF5X29mX3dlZWssIE9UQiwgT1RCX3RvX2JlX2N4bCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2JlaGF2LCBkYXlfb2Zfd2VlaykgJT4lDQogICAgICBzdW1tYXJpc2UodHJ1ZV9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0Kbl9kcF9ncnAyX3dkX21vZCA8LSBsZWZ0X2pvaW4obl9kcF9ncnAyX3dkLCBuX2RwX2dycDJfd2RfdGVzdCwgYnkgPSBjKCdkYXlzX3ByaW9yJywgJ3Byb2RfZ3JvdXBfYmVoYXYnLCAnZGF5X29mX3dlZWsnKSkNCm5fZHBfZ3JwMl93ZF9tb2QNCmBgYA0KDQojIyNfX0NYTCBSYXRlIGJ5IGdyb3VwcywgZGF5cyBwcmlvciwgZGF5IHR5cGVfXw0KDQpgYGB7cn0NCiNncm91cCAxJ3MgQ1hMIFJhdGUgYnkgZ3JvdXBzLCBkYXlzIHByaW9yLGRheSB0eXBlDQpuX2RwX2dycDFfZHRwIDwtIGgyX3RyYWluXzEgJT4lDQogICAgICBzZWxlY3QoZGF5c19wcmlvciwgcHJvZF9ncm91cF9wZXJjLCBkYXlfdHlwZSwgT1RCLCBPVEJfdG9fYmVfY3hsLCBtb250aCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV90eXBlKSAlPiUNCiAgICAgIHN1bW1hcmlzZShwcmVkaWN0X2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQpuX2RwX2dycDFfZHRwX3Rlc3QgPC0gaG90Ml90ZXN0XzEgJT4lDQogICAgICBzZWxlY3QoZGF5c19wcmlvciwgcHJvZF9ncm91cF9wZXJjLCBkYXlfdHlwZSwgT1RCLCBPVEJfdG9fYmVfY3hsLCBtb250aCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX3BlcmMsIGRheV90eXBlKSAlPiUNCiAgICAgIHN1bW1hcmlzZSh0cnVlX2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQpuX2RwX2dycDFfZHRwX21vZCA8LSBsZWZ0X2pvaW4obl9kcF9ncnAxX2R0cCwgbl9kcF9ncnAxX2R0cF90ZXN0LCBieSA9IGMoJ2RheXNfcHJpb3InLCAncHJvZF9ncm91cF9wZXJjJywgJ2RheV90eXBlJykpDQpuX2RwX2dycDFfZHRwX21vZA0KYGBgDQoNCmBgYHtyfQ0KI2dyb3VwIDIncyBDWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsZGF5IHR5cGUNCm5fZHBfZ3JwMl9kdHAgPC0gaDJfdHJhaW5fMiAlPiUNCiAgICAgIHNlbGVjdChkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2JlaGF2LCBkYXlfdHlwZSwgT1RCLCBPVEJfdG9fYmVfY3hsLCBtb250aCkgJT4lDQogICAgICBncm91cF9ieShkYXlzX3ByaW9yLCBwcm9kX2dyb3VwX2JlaGF2LCBkYXlfdHlwZSkgJT4lDQogICAgICBzdW1tYXJpc2UocHJlZGljdF9jeGxfcmF0ZSA9IHN1bShPVEJfdG9fYmVfY3hsKS9zdW0oT1RCKSkNCg0Kbl9kcF9ncnAyX2R0cF90ZXN0IDwtIGhvdDJfdGVzdF8yICU+JQ0KICAgICAgc2VsZWN0KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfYmVoYXYsIGRheV90eXBlLCBPVEIsIE9UQl90b19iZV9jeGwsIG1vbnRoKSAlPiUNCiAgICAgIGdyb3VwX2J5KGRheXNfcHJpb3IsIHByb2RfZ3JvdXBfYmVoYXYsIGRheV90eXBlKSAlPiUNCiAgICAgIHN1bW1hcmlzZSh0cnVlX2N4bF9yYXRlID0gc3VtKE9UQl90b19iZV9jeGwpL3N1bShPVEIpKQ0KDQpuX2RwX2dycDJfZHRwX21vZCA8LSBsZWZ0X2pvaW4obl9kcF9ncnAyX2R0cCwgbl9kcF9ncnAyX2R0cF90ZXN0LCBieSA9IGMoJ2RheXNfcHJpb3InLCAncHJvZF9ncm91cF9iZWhhdicsICdkYXlfdHlwZScpKQ0Kbl9kcF9ncnAyX2R0cF9tb2QNCmBgYA0KDQojX19QZXJmb3JtYW5jZSBFdmFsdWF0aW9uX18NCiMjX19Ib3RlbCAxIC0gQVRMX18NCiMjI19fQ1hMIFJhdGUgYnkgZGF5cyBwcmlvcl9fDQpgYGB7cn0NCiMgZm9yZWNhc3Qgb3RiIHRvIHN1cnZpdmUNCmFfZHBfZmNzIDwtIGxlZnRfam9pbihob3QxLCBhX2RwX21vZCwgYnk9ImRheXNfcHJpb3IiKSAlPiUgDQogIG11dGF0ZShmY3N0X3N2diA9IE9UQi1PVEIqcHJlZGljdF9jeGxfcmF0ZSkNCmBgYA0KDQpgYGB7cn0NCiMgTUFFDQphX2RwX21hZSA8LSBhX2RwX2ZjcyAlPiUgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJykpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BRSA9IG1hZShPVEJfdG9fc3Vydml2ZSwgZmNzdF9zdnYpKQ0KYV9kcF9tYWUNCmBgYA0KYGBge3J9DQojIE1BUEU6IHRoZSBPVEJfdG9fc3Vydml2ZSBoYXMgMCB2YWx1ZXMuIFNvIGFzayBQcm9mZXNzb3INCmFfZHBfbWFwZSA8LSBhX2RwX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlKSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQVBFID0gbWFwZShPVEJfdG9fc3Vydml2ZSwgZmNzdF9zdnYpKQ0KYV9kcF9tYXBlDQpgYGANCg0KYGBge3J9DQojIE1BU0U6IA0KIyMgQXZnIHN1cnZpdmFsIHJhdGU6DQphdmdfc3Z2X3J0IDwtIHN1bShoMV90cmFpbiRPVEJfdG9fc3Vydml2ZSkvc3VtKGgxX3RyYWluJE9UQikNCiMjIE1BU0UNCmFfZHBfbWFzZSA8LSBhX2RwX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpLA0KICAgICAgICAgYWJzX2RpZmZfMT1hYnMoT1RCX3RvX3N1cnZpdmUtZmNzdF9zdnYpLA0KICAgICAgICAgYWJzX2RpZmZfMj1hYnMoT1RCX3RvX3N1cnZpdmUtYXZnX3N2dl9ydCpPVEIpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlKSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQVNFID0gc3VtKGFic19kaWZmXzEpL3N1bShhYnNfZGlmZl8yKSkNCmFfZHBfbWFzZQ0KYGBgDQoNCiMjI19fQ1hMIFJhdGUgYnkgZ3JvdXBzLCBkYXlzIHByaW9yLCBhbmQgd2Vla2RheXNfXw0KIyMjIyBHcm91cGluZyBtZXRob2QgMQ0KYGBge3J9DQojIGZvcmVjYXN0IG90YiB0byBzdXJ2aXZlDQphX2RwX2dycDFfd2RfZmNzIDwtIGxlZnRfam9pbihob3QxX3Rlc3RfMSwgYV9kcF9ncnAxX3dkX21vZCwgYnk9YygiZGF5c19wcmlvciIsICJkYXlfb2Zfd2VlayIsICJwcm9kX2dyb3VwX3BlcmMiKSkgJT4lIA0KICBtdXRhdGUoZmNzdF9zdnYgPSBPVEItT1RCKnByZWRpY3RfY3hsX3JhdGUpDQphX2RwX2dycDFfd2RfZmNzDQpgYGANCg0KYGBge3J9DQojIE1BRQ0KYV9kcF9ncnAxX3dkX21hZSA8LSBhX2RwX2dycDFfd2RfZmNzICU+JSANCiAgZmlsdGVyKGRheXNfcHJpb3IhPTApICU+JSANCiAgbXV0YXRlKGRwX3JhbmdlID0gY2FzZV93aGVuKGRheXNfcHJpb3IgPj0xICYgZGF5c19wcmlvcjw9NyB+ICcxXzcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj04ICYgZGF5c19wcmlvcjw9MTQgfiAnOF8xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTE1ICYgZGF5c19wcmlvcjw9MjEgfiAnMTVfMjEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yMiAmIGRheXNfcHJpb3I8PTI4IH4gJzIyXzI4JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjkgfiAnMjlfMzInKSkgJT4lIA0KICBncm91cF9ieShkcF9yYW5nZSwgZGF5X29mX3dlZWssIHByb2RfZ3JvdXBfcGVyYykgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFFID0gbWFlKE9UQl90b19zdXJ2aXZlLCBmY3N0X3N2dikpDQphX2RwX2dycDFfd2RfbWFlDQpgYGANCg0KYGBge3J9DQojIE1BUEUgDQpgYGANCg0KYGBge3J9DQojIE1BU0UNCmFfZHBfZ3JwMV93ZF9tYXNlIDwtIGFfZHBfZ3JwMV93ZF9mY3MgJT4lICANCiAgZmlsdGVyKGRheXNfcHJpb3IhPTApICU+JSANCiAgbXV0YXRlKGRwX3JhbmdlID0gY2FzZV93aGVuKGRheXNfcHJpb3IgPj0xICYgZGF5c19wcmlvcjw9NyB+ICcxXzcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj04ICYgZGF5c19wcmlvcjw9MTQgfiAnOF8xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTE1ICYgZGF5c19wcmlvcjw9MjEgfiAnMTVfMjEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yMiAmIGRheXNfcHJpb3I8PTI4IH4gJzIyXzI4JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjkgfiAnMjlfMzInKSwNCiAgICAgICAgIGFic19kaWZmXzE9YWJzKE9UQl90b19zdXJ2aXZlLWZjc3Rfc3Z2KSwNCiAgICAgICAgIGFic19kaWZmXzI9YWJzKE9UQl90b19zdXJ2aXZlLWF2Z19zdnZfcnQqT1RCKSkgJT4lIA0KICBncm91cF9ieShkcF9yYW5nZSwgZGF5X29mX3dlZWssIHByb2RfZ3JvdXBfcGVyYykgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFTRSA9IHN1bShhYnNfZGlmZl8xKS9zdW0oYWJzX2RpZmZfMikpDQphX2RwX2dycDFfd2RfbWFzZQ0KYGBgDQoNCiMjIyMgR3JvdXBpbmcgbWV0aG9kIDINCg0KYGBge3J9DQojIGZvcmVjYXN0IG90YiB0byBzdXJ2aXZlDQphX2RwX2dycDJfd2RfZmNzIDwtIGxlZnRfam9pbihob3QxX3Rlc3RfMiwgYV9kcF9ncnAyX3dkX21vZCwgYnk9YygiZGF5c19wcmlvciIsICJkYXlfb2Zfd2VlayIsICJwcm9kX2dyb3VwX2JlaGF2IikpICU+JSANCiAgbXV0YXRlKGZjc3Rfc3Z2ID0gT1RCLU9UQipwcmVkaWN0X2N4bF9yYXRlKQ0KYV9kcF9ncnAyX3dkX2Zjcw0KYGBgDQoNCmBgYHtyfQ0KIyBNQUUNCmFfZHBfZ3JwMl93ZF9tYWUgPC0gYV9kcF9ncnAyX3dkX2ZjcyAlPiUgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJykpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX2JlaGF2KSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQUUgPSBtYWUoT1RCX3RvX3N1cnZpdmUsIGZjc3Rfc3Z2KSkNCmFfZHBfZ3JwMl93ZF9tYWUNCmBgYA0KDQpgYGB7cn0NCiMgTUFQRSANCmBgYA0KDQpgYGB7cn0NCiMgTUFTRQ0KYV9kcF9ncnAyX3dkX21hc2UgPC0gYV9kcF9ncnAyX3dkX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpLA0KICAgICAgICAgYWJzX2RpZmZfMT1hYnMoT1RCX3RvX3N1cnZpdmUtZmNzdF9zdnYpLA0KICAgICAgICAgYWJzX2RpZmZfMj1hYnMoT1RCX3RvX3N1cnZpdmUtYXZnX3N2dl9ydCpPVEIpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfb2Zfd2VlaywgcHJvZF9ncm91cF9iZWhhdikgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFTRSA9IHN1bShhYnNfZGlmZl8xKS9zdW0oYWJzX2RpZmZfMikpDQphX2RwX2dycDJfd2RfbWFzZQ0KYGBgDQoNCiMjIyMgR3JvdXBpbmcgbWV0aG9kIDMNCmBgYHtyfQ0KIyBmb3JlY2FzdCBvdGIgdG8gc3Vydml2ZQ0KYV9kcF9ncnAzX3dkX2ZjcyA8LSBsZWZ0X2pvaW4oaG90MV90ZXN0XzMsIGFfZHBfZ3JwM193ZF9tb2QsIGJ5PWMoImRheXNfcHJpb3IiLCAiZGF5X29mX3dlZWsiLCAicHJvZF9ncm91cF9jeGxfcmF0ZSIpKSAlPiUgDQogIG11dGF0ZShmY3N0X3N2diA9IE9UQi1PVEIqcHJlZGljdF9jeGxfcmF0ZSkNCmFfZHBfZ3JwM193ZF9mY3MNCmBgYA0KDQoNCmBgYHtyfQ0KIyBNQUUNCmFfZHBfZ3JwM193ZF9tYWUgPC0gYV9kcF9ncnAzX3dkX2ZjcyAlPiUgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJykpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX2N4bF9yYXRlKSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQUUgPSBtYWUoT1RCX3RvX3N1cnZpdmUsIGZjc3Rfc3Z2KSkNCmFfZHBfZ3JwM193ZF9tYWUNCmBgYA0KDQpgYGB7cn0NCiMgTUFQRSANCmBgYA0KDQpgYGB7cn0NCiMgTUFTRQ0KYV9kcF9ncnAzX3dkX21hc2UgPC0gYV9kcF9ncnAzX3dkX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpLA0KICAgICAgICAgYWJzX2RpZmZfMT1hYnMoT1RCX3RvX3N1cnZpdmUtZmNzdF9zdnYpLA0KICAgICAgICAgYWJzX2RpZmZfMj1hYnMoT1RCX3RvX3N1cnZpdmUtYXZnX3N2dl9ydCpPVEIpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfb2Zfd2VlaywgcHJvZF9ncm91cF9jeGxfcmF0ZSkgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFTRSA9IHN1bShhYnNfZGlmZl8xKS9zdW0oYWJzX2RpZmZfMikpDQphX2RwX2dycDNfd2RfbWFzZQ0KYGBgDQoNCg0KIyMjX19DWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsIGRheSB0eXBlX18NCiMjIyMgR3JvdXBpbmcgbWV0aG9kIDENCmBgYHtyfQ0KIyBmb3JlY2FzdCBvdGIgdG8gc3Vydml2ZQ0KYV9kcF9ncnAxX2R0cF9mY3MgPC0gbGVmdF9qb2luKGhvdDFfdGVzdF8xLCBhX2RwX2dycDFfZHRwX21vZCwgYnk9YygiZGF5c19wcmlvciIsICJkYXlfdHlwZSIsICJwcm9kX2dyb3VwX3BlcmMiKSkgJT4lIA0KICBtdXRhdGUoZmNzdF9zdnYgPSBPVEItT1RCKnByZWRpY3RfY3hsX3JhdGUpDQphX2RwX2dycDFfZHRwX2Zjcw0KYGBgDQpgYGB7cn0NCiMgTUFFDQphX2RwX2dycDFfZHRwX21hZSA8LSBhX2RwX2dycDFfZHRwX2ZjcyAlPiUgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJykpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX3BlcmMpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BRSA9IG1hZShPVEJfdG9fc3Vydml2ZSwgZmNzdF9zdnYpKQ0KYV9kcF9ncnAxX2R0cF9tYWUNCmBgYA0KDQpgYGB7cn0NCiMgTUFQRSANCmBgYA0KDQpgYGB7cn0NCiMgTUFTRQ0KYV9kcF9ncnAxX2R0cF9tYXNlIDwtIGFfZHBfZ3JwMV9kdHBfZmNzICU+JSAgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJyksDQogICAgICAgICBhYnNfZGlmZl8xPWFicyhPVEJfdG9fc3Vydml2ZS1mY3N0X3N2diksDQogICAgICAgICBhYnNfZGlmZl8yPWFicyhPVEJfdG9fc3Vydml2ZS1hdmdfc3Z2X3J0Kk9UQikpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX3BlcmMpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BU0UgPSBzdW0oYWJzX2RpZmZfMSkvc3VtKGFic19kaWZmXzIpKQ0KYV9kcF9ncnAxX2R0cF9tYXNlDQpgYGANCg0KIyMjIyBHcm91cGluZyBtZXRob2QgMg0KDQpgYGB7cn0NCiMgZm9yZWNhc3Qgb3RiIHRvIHN1cnZpdmUNCmFfZHBfZ3JwMl9kdHBfZmNzIDwtIGxlZnRfam9pbihob3QxX3Rlc3RfMiwgYV9kcF9ncnAyX2R0cF9tb2QsIGJ5PWMoImRheXNfcHJpb3IiLCAiZGF5X3R5cGUiLCAicHJvZF9ncm91cF9iZWhhdiIpKSAlPiUgDQogIG11dGF0ZShmY3N0X3N2diA9IE9UQi1PVEIqcHJlZGljdF9jeGxfcmF0ZSkNCmFfZHBfZ3JwMl9kdHBfZmNzDQpgYGANCg0KYGBge3J9DQojIE1BRQ0KYV9kcF9ncnAyX2R0cF9tYWUgPC0gYV9kcF9ncnAyX2R0cF9mY3MgJT4lIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfdHlwZSwgcHJvZF9ncm91cF9iZWhhdikgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFFID0gbWFlKE9UQl90b19zdXJ2aXZlLCBmY3N0X3N2dikpDQphX2RwX2dycDJfZHRwX21hZQ0KYGBgDQoNCmBgYHtyfQ0KIyBNQVBFIA0KYGBgDQoNCmBgYHtyfQ0KIyBNQVNFDQphX2RwX2dycDJfZHRwX21hc2UgPC0gYV9kcF9ncnAyX2R0cF9mY3MgJT4lICANCiAgZmlsdGVyKGRheXNfcHJpb3IhPTApICU+JSANCiAgbXV0YXRlKGRwX3JhbmdlID0gY2FzZV93aGVuKGRheXNfcHJpb3IgPj0xICYgZGF5c19wcmlvcjw9NyB+ICcxXzcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj04ICYgZGF5c19wcmlvcjw9MTQgfiAnOF8xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTE1ICYgZGF5c19wcmlvcjw9MjEgfiAnMTVfMjEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yMiAmIGRheXNfcHJpb3I8PTI4IH4gJzIyXzI4JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjkgfiAnMjlfMzInKSwNCiAgICAgICAgIGFic19kaWZmXzE9YWJzKE9UQl90b19zdXJ2aXZlLWZjc3Rfc3Z2KSwNCiAgICAgICAgIGFic19kaWZmXzI9YWJzKE9UQl90b19zdXJ2aXZlLWF2Z19zdnZfcnQqT1RCKSkgJT4lIA0KICBncm91cF9ieShkcF9yYW5nZSwgZGF5X3R5cGUsIHByb2RfZ3JvdXBfYmVoYXYpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BU0UgPSBzdW0oYWJzX2RpZmZfMSkvc3VtKGFic19kaWZmXzIpKQ0KYV9kcF9ncnAyX2R0cF9tYXNlDQpgYGANCg0KIyMjIyBHcm91cGluZyBtZXRob2QgMw0KYGBge3J9DQojIGZvcmVjYXN0IG90YiB0byBzdXJ2aXZlDQphX2RwX2dycDNfZHRwX2ZjcyA8LSBsZWZ0X2pvaW4oaG90MV90ZXN0XzMsIGFfZHBfZ3JwM19kdHBfbW9kLCBieT1jKCJkYXlzX3ByaW9yIiwgImRheV90eXBlIiwgInByb2RfZ3JvdXBfY3hsX3JhdGUiKSkgJT4lIA0KICBtdXRhdGUoZmNzdF9zdnYgPSBPVEItT1RCKnByZWRpY3RfY3hsX3JhdGUpDQphX2RwX2dycDNfZHRwX2Zjcw0KYGBgDQoNCg0KYGBge3J9DQojIE1BRQ0KYV9kcF9ncnAzX2R0cF9tYWUgPC0gYV9kcF9ncnAzX2R0cF9mY3MgJT4lIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfdHlwZSwgcHJvZF9ncm91cF9jeGxfcmF0ZSkgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFFID0gbWFlKE9UQl90b19zdXJ2aXZlLCBmY3N0X3N2dikpDQphX2RwX2dycDNfZHRwX21hZQ0KYGBgDQoNCmBgYHtyfQ0KIyBNQVBFIA0KYGBgDQoNCmBgYHtyfQ0KIyBNQVNFDQphX2RwX2dycDNfZHRwX21hc2UgPC0gYV9kcF9ncnAzX2R0cF9mY3MgJT4lICANCiAgZmlsdGVyKGRheXNfcHJpb3IhPTApICU+JSANCiAgbXV0YXRlKGRwX3JhbmdlID0gY2FzZV93aGVuKGRheXNfcHJpb3IgPj0xICYgZGF5c19wcmlvcjw9NyB+ICcxXzcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj04ICYgZGF5c19wcmlvcjw9MTQgfiAnOF8xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTE1ICYgZGF5c19wcmlvcjw9MjEgfiAnMTVfMjEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yMiAmIGRheXNfcHJpb3I8PTI4IH4gJzIyXzI4JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjkgfiAnMjlfMzInKSwNCiAgICAgICAgIGFic19kaWZmXzE9YWJzKE9UQl90b19zdXJ2aXZlLWZjc3Rfc3Z2KSwNCiAgICAgICAgIGFic19kaWZmXzI9YWJzKE9UQl90b19zdXJ2aXZlLWF2Z19zdnZfcnQqT1RCKSkgJT4lIA0KICBncm91cF9ieShkcF9yYW5nZSwgZGF5X3R5cGUsIHByb2RfZ3JvdXBfY3hsX3JhdGUpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BU0UgPSBzdW0oYWJzX2RpZmZfMSkvc3VtKGFic19kaWZmXzIpKQ0KYV9kcF9ncnAzX2R0cF9tYXNlDQpgYGANCg0KDQoNCiMjX19Ib3RlbCAyIC0gQVRMX18NCiMjI19fQ1hMIFJhdGUgYnkgZGF5cyBwcmlvcl9fDQpgYGB7cn0NCiMgZm9yZWNhc3Qgb3RiIHRvIHN1cnZpdmUNCm5fZHBfZmNzIDwtIGxlZnRfam9pbihob3QyLCBuX2RwX21vZCwgYnk9ImRheXNfcHJpb3IiKSAlPiUgDQogIG11dGF0ZShmY3N0X3N2diA9IE9UQi1PVEIqcHJlZGljdF9jeGxfcmF0ZSkNCmBgYA0KDQpgYGB7cn0NCiMgTUFFDQpuX2RwX21hZSA8LSBuX2RwX2ZjcyAlPiUgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJykpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BRSA9IG1hZShPVEJfdG9fc3Vydml2ZSwgZmNzdF9zdnYpKQ0Kbl9kcF9tYWUNCmBgYA0KDQpgYGB7cn0NCiMgTUFQRTogdGhlIE9UQl90b19zdXJ2aXZlIGRvZXNuJ3QgaGF2ZSAwIHZhbHVlcy4NCm5fZHBfbWFwZSA8LSBuX2RwX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlKSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQVBFID0gbWFwZShPVEJfdG9fc3Vydml2ZSwgZmNzdF9zdnYpKQ0Kbl9kcF9tYXBlDQpgYGANCg0KYGBge3J9DQojIE1BU0U6IA0KIyMgQXZnIHN1cnZpdmFsIHJhdGU6DQphdmdfc3Z2X3J0XzIgPC0gc3VtKGgyX3RyYWluJE9UQl90b19zdXJ2aXZlKS9zdW0oaDJfdHJhaW4kT1RCKQ0KIyMgTUFTRQ0Kbl9kcF9tYXNlIDwtIG5fZHBfZmNzICU+JSAgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJyksDQogICAgICAgICBhYnNfZGlmZl8xPWFicyhPVEJfdG9fc3Vydml2ZS1mY3N0X3N2diksDQogICAgICAgICBhYnNfZGlmZl8yPWFicyhPVEJfdG9fc3Vydml2ZS1hdmdfc3Z2X3J0Kk9UQikpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BU0UgPSBzdW0oYWJzX2RpZmZfMSkvc3VtKGFic19kaWZmXzIpKQ0Kbl9kcF9tYXNlDQpgYGANCg0KIyMjX19DWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsIGFuZCB3ZWVrZGF5c19fDQojIyMjIEdyb3VwaW5nIG1ldGhvZCAxDQpgYGB7cn0NCiMgZm9yZWNhc3Qgb3RiIHRvIHN1cnZpdmUNCm5fZHBfZ3JwMV93ZF9mY3MgPC0gbGVmdF9qb2luKGhvdDJfdGVzdF8xLCBuX2RwX2dycDFfd2RfbW9kLCBieT1jKCJkYXlzX3ByaW9yIiwgImRheV9vZl93ZWVrIiwgInByb2RfZ3JvdXBfcGVyYyIpKSAlPiUgDQogIG11dGF0ZShmY3N0X3N2diA9IE9UQi1PVEIqcHJlZGljdF9jeGxfcmF0ZSkNCm5fZHBfZ3JwMV93ZF9mY3MNCmBgYA0KDQpgYGB7cn0NCiMgTUFFDQpuX2RwX2dycDFfd2RfbWFlIDwtIG5fZHBfZ3JwMV93ZF9mY3MgJT4lIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfb2Zfd2VlaywgcHJvZF9ncm91cF9wZXJjKSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQUUgPSBtYWUoT1RCX3RvX3N1cnZpdmUsIGZjc3Rfc3Z2KSkNCm5fZHBfZ3JwMV93ZF9tYWUNCmBgYA0KDQpgYGB7cn0NCiMgTUFQRTogdGhlIE9UQl90b19zdXJ2aXZlIGRvZXNuJ3QgaGF2ZSAwIHZhbHVlcy4NCm5fZHBfZ3JwMV93ZF9tYXBlIDwtIG5fZHBfZ3JwMV93ZF9mY3MgJT4lICANCiAgZmlsdGVyKGRheXNfcHJpb3IhPTApICU+JSANCiAgbXV0YXRlKGRwX3JhbmdlID0gY2FzZV93aGVuKGRheXNfcHJpb3IgPj0xICYgZGF5c19wcmlvcjw9NyB+ICcxXzcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj04ICYgZGF5c19wcmlvcjw9MTQgfiAnOF8xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTE1ICYgZGF5c19wcmlvcjw9MjEgfiAnMTVfMjEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yMiAmIGRheXNfcHJpb3I8PTI4IH4gJzIyXzI4JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjkgfiAnMjlfMzInKSkgJT4lIA0KICBncm91cF9ieShkcF9yYW5nZSwgZGF5X29mX3dlZWssIHByb2RfZ3JvdXBfcGVyYykgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFQRSA9IG1hcGUoT1RCX3RvX3N1cnZpdmUsIGZjc3Rfc3Z2KSkNCm5fZHBfZ3JwMV93ZF9tYXBlDQoNCmBgYA0KDQpgYGB7cn0NCiMgTUFTRQ0Kbl9kcF9ncnAxX3dkX21hc2UgPC0gbl9kcF9ncnAxX3dkX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpLA0KICAgICAgICAgYWJzX2RpZmZfMT1hYnMoT1RCX3RvX3N1cnZpdmUtZmNzdF9zdnYpLA0KICAgICAgICAgYWJzX2RpZmZfMj1hYnMoT1RCX3RvX3N1cnZpdmUtYXZnX3N2dl9ydF8yKk9UQikpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX3BlcmMpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BU0UgPSBzdW0oYWJzX2RpZmZfMSkvc3VtKGFic19kaWZmXzIpKQ0Kbl9kcF9ncnAxX3dkX21hc2UNCmBgYA0KDQojIyMjIEdyb3VwaW5nIG1ldGhvZCAyDQoNCmBgYHtyfQ0KIyBmb3JlY2FzdCBvdGIgdG8gc3Vydml2ZQ0Kbl9kcF9ncnAyX3dkX2ZjcyA8LSBsZWZ0X2pvaW4oaG90Ml90ZXN0XzIsIG5fZHBfZ3JwMl93ZF9tb2QsIGJ5PWMoImRheXNfcHJpb3IiLCAiZGF5X29mX3dlZWsiLCAicHJvZF9ncm91cF9iZWhhdiIpKSAlPiUgDQogIG11dGF0ZShmY3N0X3N2diA9IE9UQi1PVEIqcHJlZGljdF9jeGxfcmF0ZSkNCm5fZHBfZ3JwMl93ZF9mY3MNCmBgYA0KDQoNCg0KYGBge3J9DQojIE1BRQ0Kbl9kcF9ncnAyX3dkX21hZSA8LSBuX2RwX2dycDJfd2RfZmNzICU+JSANCiAgZmlsdGVyKGRheXNfcHJpb3IhPTApICU+JSANCiAgbXV0YXRlKGRwX3JhbmdlID0gY2FzZV93aGVuKGRheXNfcHJpb3IgPj0xICYgZGF5c19wcmlvcjw9NyB+ICcxXzcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj04ICYgZGF5c19wcmlvcjw9MTQgfiAnOF8xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTE1ICYgZGF5c19wcmlvcjw9MjEgfiAnMTVfMjEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yMiAmIGRheXNfcHJpb3I8PTI4IH4gJzIyXzI4JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjkgfiAnMjlfMzInKSkgJT4lIA0KICBncm91cF9ieShkcF9yYW5nZSwgZGF5X29mX3dlZWssIHByb2RfZ3JvdXBfYmVoYXYpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BRSA9IG1hZShPVEJfdG9fc3Vydml2ZSwgZmNzdF9zdnYpKQ0Kbl9kcF9ncnAyX3dkX21hZQ0KYGBgDQoNCmBgYHtyfQ0KIyBNQVBFOiB0aGUgT1RCX3RvX3N1cnZpdmUgZG9lc24ndCBoYXZlIDAgdmFsdWVzLg0Kbl9kcF9ncnAyX3dkX21hcGUgPC0gbl9kcF9ncnAyX3dkX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfb2Zfd2VlaywgcHJvZF9ncm91cF9iZWhhdikgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFQRSA9IG1hcGUoT1RCX3RvX3N1cnZpdmUsIGZjc3Rfc3Z2KSkNCm5fZHBfZ3JwMl93ZF9tYXBlDQoNCmBgYA0KDQpgYGB7cn0NCiMgTUFTRQ0Kbl9kcF9ncnAyX3dkX21hc2UgPC0gbl9kcF9ncnAyX3dkX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpLA0KICAgICAgICAgYWJzX2RpZmZfMT1hYnMoT1RCX3RvX3N1cnZpdmUtZmNzdF9zdnYpLA0KICAgICAgICAgYWJzX2RpZmZfMj1hYnMoT1RCX3RvX3N1cnZpdmUtYXZnX3N2dl9ydF8yKk9UQikpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX2JlaGF2KSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQVNFID0gc3VtKGFic19kaWZmXzEpL3N1bShhYnNfZGlmZl8yKSkNCm5fZHBfZ3JwMl93ZF9tYXNlDQpgYGANCg0KIyMjX19DWEwgUmF0ZSBieSBncm91cHMsIGRheXMgcHJpb3IsIGRheSB0eXBlX18NCiMjIyMgR3JvdXBpbmcgbWV0aG9kIDENCmBgYHtyfQ0KIyBmb3JlY2FzdCBvdGIgdG8gc3Vydml2ZQ0Kbl9kcF9ncnAxX2R0cF9mY3MgPC0gbGVmdF9qb2luKGhvdDJfdGVzdF8xLCBuX2RwX2dycDFfZHRwX21vZCwgYnk9YygiZGF5c19wcmlvciIsICJkYXlfdHlwZSIsICJwcm9kX2dyb3VwX3BlcmMiKSkgJT4lIA0KICBtdXRhdGUoZmNzdF9zdnYgPSBPVEItT1RCKnByZWRpY3RfY3hsX3JhdGUpDQpuX2RwX2dycDFfZHRwX2Zjcw0KYGBgDQpgYGB7cn0NCiMgTUFFDQpuX2RwX2dycDFfZHRwX21hZSA8LSBuX2RwX2dycDFfZHRwX2ZjcyAlPiUgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJykpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX3BlcmMpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BRSA9IG1hZShPVEJfdG9fc3Vydml2ZSwgZmNzdF9zdnYpKQ0Kbl9kcF9ncnAxX2R0cF9tYWUNCmBgYA0KDQpgYGB7cn0NCiMgTUFQRTogdGhlIE9UQl90b19zdXJ2aXZlIGluIEdPVkVSTk1FTlQgY29udGFpbnMgMCB2YWx1ZXMsIHNvIE1BUEUgaXMgSU5GDQpuX2RwX2dycDFfZHRwX21hcGUgPC0gbl9kcF9ncnAxX2R0cF9mY3MgJT4lICANCiAgZmlsdGVyKGRheXNfcHJpb3IhPTApICU+JSANCiAgbXV0YXRlKGRwX3JhbmdlID0gY2FzZV93aGVuKGRheXNfcHJpb3IgPj0xICYgZGF5c19wcmlvcjw9NyB+ICcxXzcnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj04ICYgZGF5c19wcmlvcjw9MTQgfiAnOF8xNCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTE1ICYgZGF5c19wcmlvcjw9MjEgfiAnMTVfMjEnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yMiAmIGRheXNfcHJpb3I8PTI4IH4gJzIyXzI4JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjkgfiAnMjlfMzInKSkgJT4lIA0KICBncm91cF9ieShkcF9yYW5nZSwgZGF5X3R5cGUsIHByb2RfZ3JvdXBfcGVyYykgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFQRSA9IG1hcGUoT1RCX3RvX3N1cnZpdmUsIGZjc3Rfc3Z2KSkNCm5fZHBfZ3JwMV9kdHBfbWFwZQ0KDQoNCmBgYA0KDQpgYGB7cn0NCiMgTUFTRQ0Kbl9kcF9ncnAxX2R0cF9tYXNlIDwtIG5fZHBfZ3JwMV9kdHBfZmNzICU+JSAgDQogIGZpbHRlcihkYXlzX3ByaW9yIT0wKSAlPiUgDQogIG11dGF0ZShkcF9yYW5nZSA9IGNhc2Vfd2hlbihkYXlzX3ByaW9yID49MSAmIGRheXNfcHJpb3I8PTcgfiAnMV83JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49OCAmIGRheXNfcHJpb3I8PTE0IH4gJzhfMTQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0xNSAmIGRheXNfcHJpb3I8PTIxIH4gJzE1XzIxJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MjIgJiBkYXlzX3ByaW9yPD0yOCB+ICcyMl8yOCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTI5IH4gJzI5XzMyJyksDQogICAgICAgICBhYnNfZGlmZl8xPWFicyhPVEJfdG9fc3Vydml2ZS1mY3N0X3N2diksDQogICAgICAgICBhYnNfZGlmZl8yPWFicyhPVEJfdG9fc3Vydml2ZS1hdmdfc3Z2X3J0Kk9UQikpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV9vZl93ZWVrLCBwcm9kX2dyb3VwX3BlcmMpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5BU0UgPSBzdW0oYWJzX2RpZmZfMSkvc3VtKGFic19kaWZmXzIpKQ0Kbl9kcF9ncnAxX2R0cF9tYXNlDQpgYGANCg0KIyMjIyBHcm91cGluZyBtZXRob2QgMg0KYGBge3J9DQojIGZvcmVjYXN0IG90YiB0byBzdXJ2aXZlDQpuX2RwX2dycDJfZHRwX2ZjcyA8LSBsZWZ0X2pvaW4oaG90Ml90ZXN0XzIsIG5fZHBfZ3JwMl9kdHBfbW9kLCBieT1jKCJkYXlzX3ByaW9yIiwgImRheV90eXBlIiwgInByb2RfZ3JvdXBfYmVoYXYiKSkgJT4lIA0KICBtdXRhdGUoZmNzdF9zdnYgPSBPVEItT1RCKnByZWRpY3RfY3hsX3JhdGUpDQpuX2RwX2dycDJfZHRwX2Zjcw0KYGBgDQoNCg0KYGBge3J9DQojIE1BRQ0Kbl9kcF9ncnAyX2R0cF9tYWUgPC0gbl9kcF9ncnAyX2R0cF9mY3MgJT4lIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfdHlwZSwgcHJvZF9ncm91cF9iZWhhdikgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFFID0gbWFlKE9UQl90b19zdXJ2aXZlLCBmY3N0X3N2dikpDQpuX2RwX2dycDJfZHRwX21hZQ0KYGBgDQoNCmBgYHtyfQ0KIyBNQVBFOiB0aGUgT1RCX3RvX3N1cnZpdmUgaW4gR09WRVJOTUVOVCBjb250YWlucyAwIHZhbHVlcywgc28gTUFQRSBpcyBJTkYNCm5fZHBfZ3JwMl9kdHBfbWFwZSA8LSBuX2RwX2dycDJfZHRwX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpKSAlPiUgDQogIGdyb3VwX2J5KGRwX3JhbmdlLCBkYXlfdHlwZSwgcHJvZF9ncm91cF9iZWhhdikgJT4lIA0KICBzdW1tYXJpc2UobWVhbkFQRSA9IG1hcGUoT1RCX3RvX3N1cnZpdmUsIGZjc3Rfc3Z2KSkNCm5fZHBfZ3JwMl9kdHBfbWFwZQ0KDQpgYGANCg0KYGBge3J9DQojIE1BU0UNCm5fZHBfZ3JwMl9kdHBfbWFzZSA8LSBuX2RwX2dycDJfZHRwX2ZjcyAlPiUgIA0KICBmaWx0ZXIoZGF5c19wcmlvciE9MCkgJT4lIA0KICBtdXRhdGUoZHBfcmFuZ2UgPSBjYXNlX3doZW4oZGF5c19wcmlvciA+PTEgJiBkYXlzX3ByaW9yPD03IH4gJzFfNycsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTggJiBkYXlzX3ByaW9yPD0xNCB+ICc4XzE0JywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXlzX3ByaW9yID49MTUgJiBkYXlzX3ByaW9yPD0yMSB+ICcxNV8yMScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF5c19wcmlvciA+PTIyICYgZGF5c19wcmlvcjw9MjggfiAnMjJfMjgnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRheXNfcHJpb3IgPj0yOSB+ICcyOV8zMicpLA0KICAgICAgICAgYWJzX2RpZmZfMT1hYnMoT1RCX3RvX3N1cnZpdmUtZmNzdF9zdnYpLA0KICAgICAgICAgYWJzX2RpZmZfMj1hYnMoT1RCX3RvX3N1cnZpdmUtYXZnX3N2dl9ydF8yKk9UQikpICU+JSANCiAgZ3JvdXBfYnkoZHBfcmFuZ2UsIGRheV90eXBlLCBwcm9kX2dyb3VwX2JlaGF2KSAlPiUgDQogIHN1bW1hcmlzZShtZWFuQVNFID0gc3VtKGFic19kaWZmXzEpL3N1bShhYnNfZGlmZl8yKSkNCm5fZHBfZ3JwMl9kdHBfbWFzZQ0KYGBg